1711 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * QLogic iSCSI Offload Driver4 * Copyright (c) 2016 Cavium Inc.5 */6 7#include <linux/blkdev.h>8#include <linux/etherdevice.h>9#include <linux/if_ether.h>10#include <linux/if_vlan.h>11#include <scsi/scsi_tcq.h>12 13#include "qedi.h"14#include "qedi_iscsi.h"15#include "qedi_gbl.h"16 17int qedi_recover_all_conns(struct qedi_ctx *qedi)18{19 struct qedi_conn *qedi_conn;20 int i;21 22 for (i = 0; i < qedi->max_active_conns; i++) {23 qedi_conn = qedi_get_conn_from_id(qedi, i);24 if (!qedi_conn)25 continue;26 27 qedi_start_conn_recovery(qedi, qedi_conn);28 }29 30 return SUCCESS;31}32 33static int qedi_eh_host_reset(struct scsi_cmnd *cmd)34{35 struct Scsi_Host *shost = cmd->device->host;36 struct qedi_ctx *qedi;37 38 qedi = iscsi_host_priv(shost);39 40 return qedi_recover_all_conns(qedi);41}42 43const struct scsi_host_template qedi_host_template = {44 .module = THIS_MODULE,45 .name = "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver",46 .proc_name = QEDI_MODULE_NAME,47 .queuecommand = iscsi_queuecommand,48 .eh_timed_out = iscsi_eh_cmd_timed_out,49 .eh_abort_handler = iscsi_eh_abort,50 .eh_device_reset_handler = iscsi_eh_device_reset,51 .eh_target_reset_handler = iscsi_eh_recover_target,52 .eh_host_reset_handler = qedi_eh_host_reset,53 .target_alloc = iscsi_target_alloc,54 .change_queue_depth = scsi_change_queue_depth,55 .can_queue = QEDI_MAX_ISCSI_TASK,56 .this_id = -1,57 .sg_tablesize = QEDI_ISCSI_MAX_BDS_PER_CMD,58 .max_sectors = 0xffff,59 .dma_boundary = QEDI_HW_DMA_BOUNDARY,60 .cmd_per_lun = 128,61 .shost_groups = qedi_shost_groups,62 .cmd_size = sizeof(struct iscsi_cmd),63};64 65static void qedi_conn_free_login_resources(struct qedi_ctx *qedi,66 struct qedi_conn *qedi_conn)67{68 if (qedi_conn->gen_pdu.resp_bd_tbl) {69 dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,70 qedi_conn->gen_pdu.resp_bd_tbl,71 qedi_conn->gen_pdu.resp_bd_dma);72 qedi_conn->gen_pdu.resp_bd_tbl = NULL;73 }74 75 if (qedi_conn->gen_pdu.req_bd_tbl) {76 dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,77 qedi_conn->gen_pdu.req_bd_tbl,78 qedi_conn->gen_pdu.req_bd_dma);79 qedi_conn->gen_pdu.req_bd_tbl = NULL;80 }81 82 if (qedi_conn->gen_pdu.resp_buf) {83 dma_free_coherent(&qedi->pdev->dev,84 ISCSI_DEF_MAX_RECV_SEG_LEN,85 qedi_conn->gen_pdu.resp_buf,86 qedi_conn->gen_pdu.resp_dma_addr);87 qedi_conn->gen_pdu.resp_buf = NULL;88 }89 90 if (qedi_conn->gen_pdu.req_buf) {91 dma_free_coherent(&qedi->pdev->dev,92 ISCSI_DEF_MAX_RECV_SEG_LEN,93 qedi_conn->gen_pdu.req_buf,94 qedi_conn->gen_pdu.req_dma_addr);95 qedi_conn->gen_pdu.req_buf = NULL;96 }97}98 99static int qedi_conn_alloc_login_resources(struct qedi_ctx *qedi,100 struct qedi_conn *qedi_conn)101{102 qedi_conn->gen_pdu.req_buf =103 dma_alloc_coherent(&qedi->pdev->dev,104 ISCSI_DEF_MAX_RECV_SEG_LEN,105 &qedi_conn->gen_pdu.req_dma_addr,106 GFP_KERNEL);107 if (!qedi_conn->gen_pdu.req_buf)108 goto login_req_buf_failure;109 110 qedi_conn->gen_pdu.req_buf_size = 0;111 qedi_conn->gen_pdu.req_wr_ptr = qedi_conn->gen_pdu.req_buf;112 113 qedi_conn->gen_pdu.resp_buf =114 dma_alloc_coherent(&qedi->pdev->dev,115 ISCSI_DEF_MAX_RECV_SEG_LEN,116 &qedi_conn->gen_pdu.resp_dma_addr,117 GFP_KERNEL);118 if (!qedi_conn->gen_pdu.resp_buf)119 goto login_resp_buf_failure;120 121 qedi_conn->gen_pdu.resp_buf_size = ISCSI_DEF_MAX_RECV_SEG_LEN;122 qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf;123 124 qedi_conn->gen_pdu.req_bd_tbl =125 dma_alloc_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,126 &qedi_conn->gen_pdu.req_bd_dma, GFP_KERNEL);127 if (!qedi_conn->gen_pdu.req_bd_tbl)128 goto login_req_bd_tbl_failure;129 130 qedi_conn->gen_pdu.resp_bd_tbl =131 dma_alloc_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,132 &qedi_conn->gen_pdu.resp_bd_dma,133 GFP_KERNEL);134 if (!qedi_conn->gen_pdu.resp_bd_tbl)135 goto login_resp_bd_tbl_failure;136 137 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SESS,138 "Allocation successful, cid=0x%x\n",139 qedi_conn->iscsi_conn_id);140 return 0;141 142login_resp_bd_tbl_failure:143 dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,144 qedi_conn->gen_pdu.req_bd_tbl,145 qedi_conn->gen_pdu.req_bd_dma);146 qedi_conn->gen_pdu.req_bd_tbl = NULL;147 148login_req_bd_tbl_failure:149 dma_free_coherent(&qedi->pdev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,150 qedi_conn->gen_pdu.resp_buf,151 qedi_conn->gen_pdu.resp_dma_addr);152 qedi_conn->gen_pdu.resp_buf = NULL;153login_resp_buf_failure:154 dma_free_coherent(&qedi->pdev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,155 qedi_conn->gen_pdu.req_buf,156 qedi_conn->gen_pdu.req_dma_addr);157 qedi_conn->gen_pdu.req_buf = NULL;158login_req_buf_failure:159 iscsi_conn_printk(KERN_ERR, qedi_conn->cls_conn->dd_data,160 "login resource alloc failed!!\n");161 return -ENOMEM;162}163 164static void qedi_destroy_cmd_pool(struct qedi_ctx *qedi,165 struct iscsi_session *session)166{167 int i;168 169 for (i = 0; i < session->cmds_max; i++) {170 struct iscsi_task *task = session->cmds[i];171 struct qedi_cmd *cmd = task->dd_data;172 173 if (cmd->io_tbl.sge_tbl)174 dma_free_coherent(&qedi->pdev->dev,175 QEDI_ISCSI_MAX_BDS_PER_CMD *176 sizeof(struct scsi_sge),177 cmd->io_tbl.sge_tbl,178 cmd->io_tbl.sge_tbl_dma);179 180 if (cmd->sense_buffer)181 dma_free_coherent(&qedi->pdev->dev,182 SCSI_SENSE_BUFFERSIZE,183 cmd->sense_buffer,184 cmd->sense_buffer_dma);185 }186}187 188static int qedi_alloc_sget(struct qedi_ctx *qedi, struct iscsi_session *session,189 struct qedi_cmd *cmd)190{191 struct qedi_io_bdt *io = &cmd->io_tbl;192 struct scsi_sge *sge;193 194 io->sge_tbl = dma_alloc_coherent(&qedi->pdev->dev,195 QEDI_ISCSI_MAX_BDS_PER_CMD *196 sizeof(*sge),197 &io->sge_tbl_dma, GFP_KERNEL);198 if (!io->sge_tbl) {199 iscsi_session_printk(KERN_ERR, session,200 "Could not allocate BD table.\n");201 return -ENOMEM;202 }203 204 io->sge_valid = 0;205 return 0;206}207 208static int qedi_setup_cmd_pool(struct qedi_ctx *qedi,209 struct iscsi_session *session)210{211 int i;212 213 for (i = 0; i < session->cmds_max; i++) {214 struct iscsi_task *task = session->cmds[i];215 struct qedi_cmd *cmd = task->dd_data;216 217 task->hdr = &cmd->hdr;218 task->hdr_max = sizeof(struct iscsi_hdr);219 220 if (qedi_alloc_sget(qedi, session, cmd))221 goto free_sgets;222 223 cmd->sense_buffer = dma_alloc_coherent(&qedi->pdev->dev,224 SCSI_SENSE_BUFFERSIZE,225 &cmd->sense_buffer_dma,226 GFP_KERNEL);227 if (!cmd->sense_buffer)228 goto free_sgets;229 }230 231 return 0;232 233free_sgets:234 qedi_destroy_cmd_pool(qedi, session);235 return -ENOMEM;236}237 238static struct iscsi_cls_session *239qedi_session_create(struct iscsi_endpoint *ep, u16 cmds_max,240 u16 qdepth, uint32_t initial_cmdsn)241{242 struct Scsi_Host *shost;243 struct iscsi_cls_session *cls_session;244 struct qedi_ctx *qedi;245 struct qedi_endpoint *qedi_ep;246 247 if (!ep)248 return NULL;249 250 qedi_ep = ep->dd_data;251 shost = qedi_ep->qedi->shost;252 qedi = iscsi_host_priv(shost);253 254 if (cmds_max > qedi->max_sqes)255 cmds_max = qedi->max_sqes;256 else if (cmds_max < QEDI_SQ_WQES_MIN)257 cmds_max = QEDI_SQ_WQES_MIN;258 259 cls_session = iscsi_session_setup(&qedi_iscsi_transport, shost,260 cmds_max, 0, sizeof(struct qedi_cmd),261 initial_cmdsn, ISCSI_MAX_TARGET);262 if (!cls_session) {263 QEDI_ERR(&qedi->dbg_ctx,264 "Failed to setup session for ep=%p\n", qedi_ep);265 return NULL;266 }267 268 if (qedi_setup_cmd_pool(qedi, cls_session->dd_data)) {269 QEDI_ERR(&qedi->dbg_ctx,270 "Failed to setup cmd pool for ep=%p\n", qedi_ep);271 goto session_teardown;272 }273 274 return cls_session;275 276session_teardown:277 iscsi_session_teardown(cls_session);278 return NULL;279}280 281static void qedi_session_destroy(struct iscsi_cls_session *cls_session)282{283 struct iscsi_session *session = cls_session->dd_data;284 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);285 struct qedi_ctx *qedi = iscsi_host_priv(shost);286 287 qedi_destroy_cmd_pool(qedi, session);288 iscsi_session_teardown(cls_session);289}290 291static struct iscsi_cls_conn *292qedi_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid)293{294 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);295 struct qedi_ctx *qedi = iscsi_host_priv(shost);296 struct iscsi_cls_conn *cls_conn;297 struct qedi_conn *qedi_conn;298 struct iscsi_conn *conn;299 300 cls_conn = iscsi_conn_setup(cls_session, sizeof(*qedi_conn),301 cid);302 if (!cls_conn) {303 QEDI_ERR(&qedi->dbg_ctx,304 "conn_new: iscsi conn setup failed, cid=0x%x, cls_sess=%p!\n",305 cid, cls_session);306 return NULL;307 }308 309 conn = cls_conn->dd_data;310 qedi_conn = conn->dd_data;311 qedi_conn->cls_conn = cls_conn;312 qedi_conn->qedi = qedi;313 qedi_conn->ep = NULL;314 qedi_conn->active_cmd_count = 0;315 INIT_LIST_HEAD(&qedi_conn->active_cmd_list);316 spin_lock_init(&qedi_conn->list_lock);317 318 if (qedi_conn_alloc_login_resources(qedi, qedi_conn)) {319 iscsi_conn_printk(KERN_ALERT, conn,320 "conn_new: login resc alloc failed, cid=0x%x, cls_sess=%p!!\n",321 cid, cls_session);322 goto free_conn;323 }324 325 return cls_conn;326 327free_conn:328 iscsi_conn_teardown(cls_conn);329 return NULL;330}331 332void qedi_mark_device_missing(struct iscsi_cls_session *cls_session)333{334 struct iscsi_session *session = cls_session->dd_data;335 struct qedi_conn *qedi_conn = session->leadconn->dd_data;336 337 spin_lock_bh(&session->frwd_lock);338 set_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags);339 spin_unlock_bh(&session->frwd_lock);340}341 342void qedi_mark_device_available(struct iscsi_cls_session *cls_session)343{344 struct iscsi_session *session = cls_session->dd_data;345 struct qedi_conn *qedi_conn = session->leadconn->dd_data;346 347 spin_lock_bh(&session->frwd_lock);348 clear_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags);349 spin_unlock_bh(&session->frwd_lock);350}351 352static int qedi_bind_conn_to_iscsi_cid(struct qedi_ctx *qedi,353 struct qedi_conn *qedi_conn)354{355 u32 iscsi_cid = qedi_conn->iscsi_conn_id;356 357 if (qedi->cid_que.conn_cid_tbl[iscsi_cid]) {358 iscsi_conn_printk(KERN_ALERT, qedi_conn->cls_conn->dd_data,359 "conn bind - entry #%d not free\n",360 iscsi_cid);361 return -EBUSY;362 }363 364 qedi->cid_que.conn_cid_tbl[iscsi_cid] = qedi_conn;365 return 0;366}367 368struct qedi_conn *qedi_get_conn_from_id(struct qedi_ctx *qedi, u32 iscsi_cid)369{370 if (!qedi->cid_que.conn_cid_tbl) {371 QEDI_ERR(&qedi->dbg_ctx, "missing conn<->cid table\n");372 return NULL;373 374 } else if (iscsi_cid >= qedi->max_active_conns) {375 QEDI_ERR(&qedi->dbg_ctx, "wrong cid #%d\n", iscsi_cid);376 return NULL;377 }378 return qedi->cid_que.conn_cid_tbl[iscsi_cid];379}380 381static int qedi_conn_bind(struct iscsi_cls_session *cls_session,382 struct iscsi_cls_conn *cls_conn,383 u64 transport_fd, int is_leading)384{385 struct iscsi_conn *conn = cls_conn->dd_data;386 struct qedi_conn *qedi_conn = conn->dd_data;387 struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);388 struct qedi_ctx *qedi = iscsi_host_priv(shost);389 struct qedi_endpoint *qedi_ep;390 struct iscsi_endpoint *ep;391 int rc = 0;392 393 ep = iscsi_lookup_endpoint(transport_fd);394 if (!ep)395 return -EINVAL;396 397 qedi_ep = ep->dd_data;398 if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) ||399 (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) {400 rc = -EINVAL;401 goto put_ep;402 }403 404 if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) {405 rc = -EINVAL;406 goto put_ep;407 }408 409 410 qedi_ep->conn = qedi_conn;411 qedi_conn->ep = qedi_ep;412 qedi_conn->iscsi_ep = ep;413 qedi_conn->iscsi_conn_id = qedi_ep->iscsi_cid;414 qedi_conn->fw_cid = qedi_ep->fw_cid;415 qedi_conn->cmd_cleanup_req = 0;416 atomic_set(&qedi_conn->cmd_cleanup_cmpl, 0);417 418 if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) {419 rc = -EINVAL;420 goto put_ep;421 }422 423 424 spin_lock_init(&qedi_conn->tmf_work_lock);425 INIT_LIST_HEAD(&qedi_conn->tmf_work_list);426 init_waitqueue_head(&qedi_conn->wait_queue);427put_ep:428 iscsi_put_endpoint(ep);429 return rc;430}431 432static int qedi_iscsi_update_conn(struct qedi_ctx *qedi,433 struct qedi_conn *qedi_conn)434{435 struct qed_iscsi_params_update *conn_info;436 struct iscsi_cls_conn *cls_conn = qedi_conn->cls_conn;437 struct iscsi_conn *conn = cls_conn->dd_data;438 struct qedi_endpoint *qedi_ep;439 int rval;440 441 qedi_ep = qedi_conn->ep;442 443 conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL);444 if (!conn_info) {445 QEDI_ERR(&qedi->dbg_ctx, "memory alloc failed\n");446 return -ENOMEM;447 }448 449 conn_info->update_flag = 0;450 451 if (conn->hdrdgst_en)452 SET_FIELD(conn_info->update_flag,453 ISCSI_CONN_UPDATE_RAMROD_PARAMS_HD_EN, true);454 if (conn->datadgst_en)455 SET_FIELD(conn_info->update_flag,456 ISCSI_CONN_UPDATE_RAMROD_PARAMS_DD_EN, true);457 if (conn->session->initial_r2t_en)458 SET_FIELD(conn_info->update_flag,459 ISCSI_CONN_UPDATE_RAMROD_PARAMS_INITIAL_R2T,460 true);461 if (conn->session->imm_data_en)462 SET_FIELD(conn_info->update_flag,463 ISCSI_CONN_UPDATE_RAMROD_PARAMS_IMMEDIATE_DATA,464 true);465 466 conn_info->max_seq_size = conn->session->max_burst;467 conn_info->max_recv_pdu_length = conn->max_recv_dlength;468 conn_info->max_send_pdu_length = conn->max_xmit_dlength;469 conn_info->first_seq_length = conn->session->first_burst;470 conn_info->exp_stat_sn = conn->exp_statsn;471 472 rval = qedi_ops->update_conn(qedi->cdev, qedi_ep->handle,473 conn_info);474 if (rval) {475 rval = -ENXIO;476 QEDI_ERR(&qedi->dbg_ctx, "Could not update connection\n");477 }478 479 kfree(conn_info);480 return rval;481}482 483static u16 qedi_calc_mss(u16 pmtu, u8 is_ipv6, u8 tcp_ts_en, u8 vlan_en)484{485 u16 mss = 0;486 u16 hdrs = TCP_HDR_LEN;487 488 if (is_ipv6)489 hdrs += IPV6_HDR_LEN;490 else491 hdrs += IPV4_HDR_LEN;492 493 mss = pmtu - hdrs;494 495 if (!mss)496 mss = DEF_MSS;497 498 return mss;499}500 501static int qedi_iscsi_offload_conn(struct qedi_endpoint *qedi_ep)502{503 struct qed_iscsi_params_offload *conn_info;504 struct qedi_ctx *qedi = qedi_ep->qedi;505 int rval;506 int i;507 508 conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL);509 if (!conn_info) {510 QEDI_ERR(&qedi->dbg_ctx,511 "Failed to allocate memory ep=%p\n", qedi_ep);512 return -ENOMEM;513 }514 515 ether_addr_copy(conn_info->src.mac, qedi_ep->src_mac);516 ether_addr_copy(conn_info->dst.mac, qedi_ep->dst_mac);517 518 conn_info->src.ip[0] = ntohl(qedi_ep->src_addr[0]);519 conn_info->dst.ip[0] = ntohl(qedi_ep->dst_addr[0]);520 521 if (qedi_ep->ip_type == TCP_IPV4) {522 conn_info->ip_version = 0;523 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,524 "After ntohl: src_addr=%pI4, dst_addr=%pI4\n",525 qedi_ep->src_addr, qedi_ep->dst_addr);526 } else {527 for (i = 1; i < 4; i++) {528 conn_info->src.ip[i] = ntohl(qedi_ep->src_addr[i]);529 conn_info->dst.ip[i] = ntohl(qedi_ep->dst_addr[i]);530 }531 532 conn_info->ip_version = 1;533 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,534 "After ntohl: src_addr=%pI6, dst_addr=%pI6\n",535 qedi_ep->src_addr, qedi_ep->dst_addr);536 }537 538 conn_info->src.port = qedi_ep->src_port;539 conn_info->dst.port = qedi_ep->dst_port;540 541 conn_info->layer_code = ISCSI_SLOW_PATH_LAYER_CODE;542 conn_info->sq_pbl_addr = qedi_ep->sq_pbl_dma;543 conn_info->vlan_id = qedi_ep->vlan_id;544 545 SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_TS_EN, 1);546 SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_DA_EN, 1);547 SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_DA_CNT_EN, 1);548 SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_KA_EN, 1);549 550 conn_info->default_cq = (qedi_ep->fw_cid % qedi->num_queues);551 552 conn_info->ka_max_probe_cnt = DEF_KA_MAX_PROBE_COUNT;553 conn_info->dup_ack_theshold = 3;554 conn_info->rcv_wnd = 65535;555 556 conn_info->ss_thresh = 65535;557 conn_info->srtt = 300;558 conn_info->rtt_var = 150;559 conn_info->flow_label = 0;560 conn_info->ka_timeout = DEF_KA_TIMEOUT;561 conn_info->ka_interval = DEF_KA_INTERVAL;562 conn_info->max_rt_time = DEF_MAX_RT_TIME;563 conn_info->ttl = DEF_TTL;564 conn_info->tos_or_tc = DEF_TOS;565 conn_info->remote_port = qedi_ep->dst_port;566 conn_info->local_port = qedi_ep->src_port;567 568 conn_info->mss = qedi_calc_mss(qedi_ep->pmtu,569 (qedi_ep->ip_type == TCP_IPV6),570 1, (qedi_ep->vlan_id != 0));571 572 conn_info->cwnd = DEF_MAX_CWND * conn_info->mss;573 conn_info->rcv_wnd_scale = 4;574 conn_info->da_timeout_value = 200;575 conn_info->ack_frequency = 2;576 577 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,578 "Default cq index [%d], mss [%d]\n",579 conn_info->default_cq, conn_info->mss);580 581 /* Prepare the doorbell parameters */582 qedi_ep->db_data.agg_flags = 0;583 qedi_ep->db_data.params = 0;584 SET_FIELD(qedi_ep->db_data.params, ISCSI_DB_DATA_DEST, DB_DEST_XCM);585 SET_FIELD(qedi_ep->db_data.params, ISCSI_DB_DATA_AGG_CMD,586 DB_AGG_CMD_MAX);587 SET_FIELD(qedi_ep->db_data.params, ISCSI_DB_DATA_AGG_VAL_SEL,588 DQ_XCM_ISCSI_SQ_PROD_CMD);589 SET_FIELD(qedi_ep->db_data.params, ISCSI_DB_DATA_BYPASS_EN, 1);590 591 /* Register doorbell with doorbell recovery mechanism */592 rval = qedi_ops->common->db_recovery_add(qedi->cdev,593 qedi_ep->p_doorbell,594 &qedi_ep->db_data,595 DB_REC_WIDTH_32B,596 DB_REC_KERNEL);597 if (rval) {598 kfree(conn_info);599 return rval;600 }601 602 rval = qedi_ops->offload_conn(qedi->cdev, qedi_ep->handle, conn_info);603 if (rval) {604 /* delete doorbell from doorbell recovery mechanism */605 rval = qedi_ops->common->db_recovery_del(qedi->cdev,606 qedi_ep->p_doorbell,607 &qedi_ep->db_data);608 609 QEDI_ERR(&qedi->dbg_ctx, "offload_conn returned %d, ep=%p\n",610 rval, qedi_ep);611 }612 613 kfree(conn_info);614 return rval;615}616 617static int qedi_conn_start(struct iscsi_cls_conn *cls_conn)618{619 struct iscsi_conn *conn = cls_conn->dd_data;620 struct qedi_conn *qedi_conn = conn->dd_data;621 struct qedi_ctx *qedi;622 int rval;623 624 qedi = qedi_conn->qedi;625 626 rval = qedi_iscsi_update_conn(qedi, qedi_conn);627 if (rval) {628 iscsi_conn_printk(KERN_ALERT, conn,629 "conn_start: FW offload conn failed.\n");630 rval = -EINVAL;631 goto start_err;632 }633 634 spin_lock(&qedi_conn->tmf_work_lock);635 qedi_conn->fw_cleanup_works = 0;636 qedi_conn->ep_disconnect_starting = false;637 spin_unlock(&qedi_conn->tmf_work_lock);638 639 qedi_conn->abrt_conn = 0;640 641 rval = iscsi_conn_start(cls_conn);642 if (rval) {643 iscsi_conn_printk(KERN_ALERT, conn,644 "iscsi_conn_start: FW offload conn failed!!\n");645 }646 647start_err:648 return rval;649}650 651static void qedi_conn_destroy(struct iscsi_cls_conn *cls_conn)652{653 struct iscsi_conn *conn = cls_conn->dd_data;654 struct qedi_conn *qedi_conn = conn->dd_data;655 struct Scsi_Host *shost;656 struct qedi_ctx *qedi;657 658 shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn));659 qedi = iscsi_host_priv(shost);660 661 qedi_conn_free_login_resources(qedi, qedi_conn);662 iscsi_conn_teardown(cls_conn);663}664 665static int qedi_ep_get_param(struct iscsi_endpoint *ep,666 enum iscsi_param param, char *buf)667{668 struct qedi_endpoint *qedi_ep = ep->dd_data;669 int len;670 671 if (!qedi_ep)672 return -ENOTCONN;673 674 switch (param) {675 case ISCSI_PARAM_CONN_PORT:676 len = sprintf(buf, "%hu\n", qedi_ep->dst_port);677 break;678 case ISCSI_PARAM_CONN_ADDRESS:679 if (qedi_ep->ip_type == TCP_IPV4)680 len = sprintf(buf, "%pI4\n", qedi_ep->dst_addr);681 else682 len = sprintf(buf, "%pI6\n", qedi_ep->dst_addr);683 break;684 default:685 return -ENOTCONN;686 }687 688 return len;689}690 691static int qedi_host_get_param(struct Scsi_Host *shost,692 enum iscsi_host_param param, char *buf)693{694 struct qedi_ctx *qedi;695 int len;696 697 qedi = iscsi_host_priv(shost);698 699 switch (param) {700 case ISCSI_HOST_PARAM_HWADDRESS:701 len = sysfs_format_mac(buf, qedi->mac, 6);702 break;703 case ISCSI_HOST_PARAM_NETDEV_NAME:704 len = sprintf(buf, "host%d\n", shost->host_no);705 break;706 case ISCSI_HOST_PARAM_IPADDRESS:707 if (qedi->ip_type == TCP_IPV4)708 len = sprintf(buf, "%pI4\n", qedi->src_ip);709 else710 len = sprintf(buf, "%pI6\n", qedi->src_ip);711 break;712 default:713 return iscsi_host_get_param(shost, param, buf);714 }715 716 return len;717}718 719static void qedi_conn_get_stats(struct iscsi_cls_conn *cls_conn,720 struct iscsi_stats *stats)721{722 struct iscsi_conn *conn = cls_conn->dd_data;723 struct qed_iscsi_stats iscsi_stats;724 struct Scsi_Host *shost;725 struct qedi_ctx *qedi;726 727 shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn));728 qedi = iscsi_host_priv(shost);729 qedi_ops->get_stats(qedi->cdev, &iscsi_stats);730 731 conn->txdata_octets = iscsi_stats.iscsi_tx_bytes_cnt;732 conn->rxdata_octets = iscsi_stats.iscsi_rx_bytes_cnt;733 conn->dataout_pdus_cnt = (uint32_t)iscsi_stats.iscsi_tx_data_pdu_cnt;734 conn->datain_pdus_cnt = (uint32_t)iscsi_stats.iscsi_rx_data_pdu_cnt;735 conn->r2t_pdus_cnt = (uint32_t)iscsi_stats.iscsi_rx_r2t_pdu_cnt;736 737 stats->txdata_octets = conn->txdata_octets;738 stats->rxdata_octets = conn->rxdata_octets;739 stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;740 stats->dataout_pdus = conn->dataout_pdus_cnt;741 stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;742 stats->datain_pdus = conn->datain_pdus_cnt;743 stats->r2t_pdus = conn->r2t_pdus_cnt;744 stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;745 stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;746 stats->digest_err = 0;747 stats->timeout_err = 0;748 strcpy(stats->custom[0].desc, "eh_abort_cnt");749 stats->custom[0].value = conn->eh_abort_cnt;750 stats->custom_length = 1;751}752 753static void qedi_iscsi_prep_generic_pdu_bd(struct qedi_conn *qedi_conn)754{755 struct scsi_sge *bd_tbl;756 757 bd_tbl = (struct scsi_sge *)qedi_conn->gen_pdu.req_bd_tbl;758 759 bd_tbl->sge_addr.hi =760 (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32);761 bd_tbl->sge_addr.lo = (u32)qedi_conn->gen_pdu.req_dma_addr;762 bd_tbl->sge_len = qedi_conn->gen_pdu.req_wr_ptr -763 qedi_conn->gen_pdu.req_buf;764 bd_tbl = (struct scsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;765 bd_tbl->sge_addr.hi =766 (u32)((u64)qedi_conn->gen_pdu.resp_dma_addr >> 32);767 bd_tbl->sge_addr.lo = (u32)qedi_conn->gen_pdu.resp_dma_addr;768 bd_tbl->sge_len = ISCSI_DEF_MAX_RECV_SEG_LEN;769}770 771static int qedi_iscsi_send_generic_request(struct iscsi_task *task)772{773 struct qedi_cmd *cmd = task->dd_data;774 struct qedi_conn *qedi_conn = cmd->conn;775 char *buf;776 int data_len;777 int rc = 0;778 779 qedi_iscsi_prep_generic_pdu_bd(qedi_conn);780 switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {781 case ISCSI_OP_LOGIN:782 qedi_send_iscsi_login(qedi_conn, task);783 break;784 case ISCSI_OP_NOOP_OUT:785 data_len = qedi_conn->gen_pdu.req_buf_size;786 buf = qedi_conn->gen_pdu.req_buf;787 if (data_len)788 rc = qedi_send_iscsi_nopout(qedi_conn, task,789 buf, data_len, 1);790 else791 rc = qedi_send_iscsi_nopout(qedi_conn, task,792 NULL, 0, 1);793 break;794 case ISCSI_OP_LOGOUT:795 rc = qedi_send_iscsi_logout(qedi_conn, task);796 break;797 case ISCSI_OP_SCSI_TMFUNC:798 rc = qedi_send_iscsi_tmf(qedi_conn, task);799 break;800 case ISCSI_OP_TEXT:801 rc = qedi_send_iscsi_text(qedi_conn, task);802 break;803 default:804 iscsi_conn_printk(KERN_ALERT, qedi_conn->cls_conn->dd_data,805 "unsupported op 0x%x\n", task->hdr->opcode);806 }807 808 return rc;809}810 811static int qedi_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)812{813 struct qedi_conn *qedi_conn = conn->dd_data;814 struct qedi_cmd *cmd = task->dd_data;815 816 memset(qedi_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN);817 818 qedi_conn->gen_pdu.req_buf_size = task->data_count;819 820 if (task->data_count) {821 memcpy(qedi_conn->gen_pdu.req_buf, task->data,822 task->data_count);823 qedi_conn->gen_pdu.req_wr_ptr =824 qedi_conn->gen_pdu.req_buf + task->data_count;825 }826 827 cmd->conn = conn->dd_data;828 return qedi_iscsi_send_generic_request(task);829}830 831static int qedi_task_xmit(struct iscsi_task *task)832{833 struct iscsi_conn *conn = task->conn;834 struct qedi_conn *qedi_conn = conn->dd_data;835 struct qedi_cmd *cmd = task->dd_data;836 struct scsi_cmnd *sc = task->sc;837 838 /* Clear now so in cleanup_task we know it didn't make it */839 cmd->scsi_cmd = NULL;840 cmd->task_id = U16_MAX;841 842 if (test_bit(QEDI_IN_SHUTDOWN, &qedi_conn->qedi->flags))843 return -ENODEV;844 845 if (test_bit(QEDI_BLOCK_IO, &qedi_conn->qedi->flags))846 return -EACCES;847 848 cmd->state = 0;849 cmd->task = NULL;850 cmd->use_slowpath = false;851 cmd->conn = qedi_conn;852 cmd->task = task;853 cmd->io_cmd_in_list = false;854 INIT_LIST_HEAD(&cmd->io_cmd);855 856 if (!sc)857 return qedi_mtask_xmit(conn, task);858 859 cmd->scsi_cmd = sc;860 return qedi_iscsi_send_ioreq(task);861}862 863static void qedi_offload_work(struct work_struct *work)864{865 struct qedi_endpoint *qedi_ep =866 container_of(work, struct qedi_endpoint, offload_work);867 struct qedi_ctx *qedi;868 int wait_delay = 5 * HZ;869 int ret;870 871 qedi = qedi_ep->qedi;872 873 ret = qedi_iscsi_offload_conn(qedi_ep);874 if (ret) {875 QEDI_ERR(&qedi->dbg_ctx,876 "offload error: iscsi_cid=%u, qedi_ep=%p, ret=%d\n",877 qedi_ep->iscsi_cid, qedi_ep, ret);878 qedi_ep->state = EP_STATE_OFLDCONN_FAILED;879 return;880 }881 882 ret = wait_event_interruptible_timeout(qedi_ep->tcp_ofld_wait,883 (qedi_ep->state ==884 EP_STATE_OFLDCONN_COMPL),885 wait_delay);886 if (ret <= 0 || qedi_ep->state != EP_STATE_OFLDCONN_COMPL) {887 qedi_ep->state = EP_STATE_OFLDCONN_FAILED;888 QEDI_ERR(&qedi->dbg_ctx,889 "Offload conn TIMEOUT iscsi_cid=%u, qedi_ep=%p\n",890 qedi_ep->iscsi_cid, qedi_ep);891 }892}893 894static struct iscsi_endpoint *895qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,896 int non_blocking)897{898 struct qedi_ctx *qedi;899 struct iscsi_endpoint *ep;900 struct qedi_endpoint *qedi_ep;901 struct sockaddr_in *addr;902 struct sockaddr_in6 *addr6;903 struct iscsi_path path_req;904 u32 msg_type = ISCSI_KEVENT_IF_DOWN;905 u32 iscsi_cid = QEDI_CID_RESERVED;906 u16 len = 0;907 char *buf = NULL;908 int ret, tmp;909 910 if (!shost) {911 ret = -ENXIO;912 QEDI_ERR(NULL, "shost is NULL\n");913 return ERR_PTR(ret);914 }915 916 if (qedi_do_not_recover) {917 ret = -ENOMEM;918 return ERR_PTR(ret);919 }920 921 qedi = iscsi_host_priv(shost);922 923 if (test_bit(QEDI_IN_OFFLINE, &qedi->flags) ||924 test_bit(QEDI_IN_RECOVERY, &qedi->flags)) {925 ret = -ENOMEM;926 return ERR_PTR(ret);927 }928 929 if (atomic_read(&qedi->link_state) != QEDI_LINK_UP) {930 QEDI_WARN(&qedi->dbg_ctx, "qedi link down\n");931 return ERR_PTR(-ENXIO);932 }933 934 ep = iscsi_create_endpoint(sizeof(struct qedi_endpoint));935 if (!ep) {936 QEDI_ERR(&qedi->dbg_ctx, "endpoint create fail\n");937 ret = -ENOMEM;938 return ERR_PTR(ret);939 }940 qedi_ep = ep->dd_data;941 memset(qedi_ep, 0, sizeof(struct qedi_endpoint));942 INIT_WORK(&qedi_ep->offload_work, qedi_offload_work);943 qedi_ep->state = EP_STATE_IDLE;944 qedi_ep->iscsi_cid = (u32)-1;945 qedi_ep->qedi = qedi;946 947 if (dst_addr->sa_family == AF_INET) {948 addr = (struct sockaddr_in *)dst_addr;949 memcpy(qedi_ep->dst_addr, &addr->sin_addr.s_addr,950 sizeof(struct in_addr));951 qedi_ep->dst_port = ntohs(addr->sin_port);952 qedi_ep->ip_type = TCP_IPV4;953 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,954 "dst_addr=%pI4, dst_port=%u\n",955 qedi_ep->dst_addr, qedi_ep->dst_port);956 } else if (dst_addr->sa_family == AF_INET6) {957 addr6 = (struct sockaddr_in6 *)dst_addr;958 memcpy(qedi_ep->dst_addr, &addr6->sin6_addr,959 sizeof(struct in6_addr));960 qedi_ep->dst_port = ntohs(addr6->sin6_port);961 qedi_ep->ip_type = TCP_IPV6;962 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,963 "dst_addr=%pI6, dst_port=%u\n",964 qedi_ep->dst_addr, qedi_ep->dst_port);965 } else {966 QEDI_ERR(&qedi->dbg_ctx, "Invalid endpoint\n");967 }968 969 ret = qedi_alloc_sq(qedi, qedi_ep);970 if (ret)971 goto ep_conn_exit;972 973 ret = qedi_ops->acquire_conn(qedi->cdev, &qedi_ep->handle,974 &qedi_ep->fw_cid, &qedi_ep->p_doorbell);975 976 if (ret) {977 QEDI_ERR(&qedi->dbg_ctx, "Could not acquire connection\n");978 ret = -ENXIO;979 goto ep_free_sq;980 }981 982 iscsi_cid = qedi_ep->handle;983 qedi_ep->iscsi_cid = iscsi_cid;984 985 init_waitqueue_head(&qedi_ep->ofld_wait);986 init_waitqueue_head(&qedi_ep->tcp_ofld_wait);987 qedi_ep->state = EP_STATE_OFLDCONN_START;988 qedi->ep_tbl[iscsi_cid] = qedi_ep;989 990 buf = (char *)&path_req;991 len = sizeof(path_req);992 memset(&path_req, 0, len);993 994 msg_type = ISCSI_KEVENT_PATH_REQ;995 path_req.handle = (u64)qedi_ep->iscsi_cid;996 path_req.pmtu = qedi->ll2_mtu;997 qedi_ep->pmtu = qedi->ll2_mtu;998 if (qedi_ep->ip_type == TCP_IPV4) {999 memcpy(&path_req.dst.v4_addr, &qedi_ep->dst_addr,1000 sizeof(struct in_addr));1001 path_req.ip_addr_len = 4;1002 } else {1003 memcpy(&path_req.dst.v6_addr, &qedi_ep->dst_addr,1004 sizeof(struct in6_addr));1005 path_req.ip_addr_len = 16;1006 }1007 1008 ret = iscsi_offload_mesg(shost, &qedi_iscsi_transport, msg_type, buf,1009 len);1010 if (ret) {1011 QEDI_ERR(&qedi->dbg_ctx,1012 "iscsi_offload_mesg() failed for cid=0x%x ret=%d\n",1013 iscsi_cid, ret);1014 goto ep_rel_conn;1015 }1016 1017 atomic_inc(&qedi->num_offloads);1018 return ep;1019 1020ep_rel_conn:1021 qedi->ep_tbl[iscsi_cid] = NULL;1022 tmp = qedi_ops->release_conn(qedi->cdev, qedi_ep->handle);1023 if (tmp)1024 QEDI_WARN(&qedi->dbg_ctx, "release_conn returned %d\n",1025 tmp);1026ep_free_sq:1027 qedi_free_sq(qedi, qedi_ep);1028ep_conn_exit:1029 iscsi_destroy_endpoint(ep);1030 return ERR_PTR(ret);1031}1032 1033static int qedi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)1034{1035 struct qedi_endpoint *qedi_ep;1036 int ret = 0;1037 1038 if (qedi_do_not_recover)1039 return 1;1040 1041 qedi_ep = ep->dd_data;1042 if (qedi_ep->state == EP_STATE_IDLE ||1043 qedi_ep->state == EP_STATE_OFLDCONN_NONE ||1044 qedi_ep->state == EP_STATE_OFLDCONN_FAILED)1045 return -1;1046 1047 if (qedi_ep->state == EP_STATE_OFLDCONN_COMPL)1048 ret = 1;1049 1050 ret = wait_event_interruptible_timeout(qedi_ep->ofld_wait,1051 QEDI_OFLD_WAIT_STATE(qedi_ep),1052 msecs_to_jiffies(timeout_ms));1053 1054 if (qedi_ep->state == EP_STATE_OFLDCONN_FAILED)1055 ret = -1;1056 1057 if (ret > 0)1058 return 1;1059 else if (!ret)1060 return 0;1061 else1062 return ret;1063}1064 1065static void qedi_cleanup_active_cmd_list(struct qedi_conn *qedi_conn)1066{1067 struct qedi_cmd *cmd, *cmd_tmp;1068 1069 spin_lock(&qedi_conn->list_lock);1070 list_for_each_entry_safe(cmd, cmd_tmp, &qedi_conn->active_cmd_list,1071 io_cmd) {1072 list_del_init(&cmd->io_cmd);1073 qedi_conn->active_cmd_count--;1074 }1075 spin_unlock(&qedi_conn->list_lock);1076}1077 1078static void qedi_ep_disconnect(struct iscsi_endpoint *ep)1079{1080 struct qedi_endpoint *qedi_ep;1081 struct qedi_conn *qedi_conn = NULL;1082 struct qedi_ctx *qedi;1083 int ret = 0;1084 int wait_delay;1085 int abrt_conn = 0;1086 1087 wait_delay = 60 * HZ + DEF_MAX_RT_TIME;1088 qedi_ep = ep->dd_data;1089 qedi = qedi_ep->qedi;1090 1091 flush_work(&qedi_ep->offload_work);1092 1093 if (qedi_ep->state == EP_STATE_OFLDCONN_START)1094 goto ep_exit_recover;1095 1096 if (qedi_ep->conn) {1097 qedi_conn = qedi_ep->conn;1098 abrt_conn = qedi_conn->abrt_conn;1099 1100 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,1101 "cid=0x%x qedi_ep=%p waiting for %d tmfs\n",1102 qedi_ep->iscsi_cid, qedi_ep,1103 qedi_conn->fw_cleanup_works);1104 1105 spin_lock(&qedi_conn->tmf_work_lock);1106 qedi_conn->ep_disconnect_starting = true;1107 while (qedi_conn->fw_cleanup_works > 0) {1108 spin_unlock(&qedi_conn->tmf_work_lock);1109 msleep(1000);1110 spin_lock(&qedi_conn->tmf_work_lock);1111 }1112 spin_unlock(&qedi_conn->tmf_work_lock);1113 1114 if (test_bit(QEDI_IN_RECOVERY, &qedi->flags)) {1115 if (qedi_do_not_recover) {1116 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,1117 "Do not recover cid=0x%x\n",1118 qedi_ep->iscsi_cid);1119 goto ep_exit_recover;1120 }1121 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,1122 "Reset recovery cid=0x%x, qedi_ep=%p, state=0x%x\n",1123 qedi_ep->iscsi_cid, qedi_ep, qedi_ep->state);1124 qedi_cleanup_active_cmd_list(qedi_conn);1125 goto ep_release_conn;1126 }1127 }1128 1129 if (qedi_do_not_recover)1130 goto ep_exit_recover;1131 1132 switch (qedi_ep->state) {1133 case EP_STATE_OFLDCONN_START:1134 case EP_STATE_OFLDCONN_NONE:1135 goto ep_release_conn;1136 case EP_STATE_OFLDCONN_FAILED:1137 break;1138 case EP_STATE_OFLDCONN_COMPL:1139 if (unlikely(!qedi_conn))1140 break;1141 1142 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,1143 "Active cmd count=%d, abrt_conn=%d, ep state=0x%x, cid=0x%x, qedi_conn=%p\n",1144 qedi_conn->active_cmd_count, abrt_conn,1145 qedi_ep->state,1146 qedi_ep->iscsi_cid,1147 qedi_ep->conn1148 );1149 1150 if (!qedi_conn->active_cmd_count)1151 abrt_conn = 0;1152 else1153 abrt_conn = 1;1154 1155 if (abrt_conn)1156 qedi_clearsq(qedi, qedi_conn, NULL);1157 break;1158 default:1159 break;1160 }1161 1162 if (!abrt_conn)1163 wait_delay += qedi->pf_params.iscsi_pf_params.two_msl_timer;1164 1165 qedi_ep->state = EP_STATE_DISCONN_START;1166 1167 if (test_bit(QEDI_IN_SHUTDOWN, &qedi->flags) ||1168 test_bit(QEDI_IN_RECOVERY, &qedi->flags))1169 goto ep_release_conn;1170 1171 /* Delete doorbell from doorbell recovery mechanism */1172 ret = qedi_ops->common->db_recovery_del(qedi->cdev,1173 qedi_ep->p_doorbell,1174 &qedi_ep->db_data);1175 1176 ret = qedi_ops->destroy_conn(qedi->cdev, qedi_ep->handle, abrt_conn);1177 if (ret) {1178 QEDI_WARN(&qedi->dbg_ctx,1179 "destroy_conn failed returned %d\n", ret);1180 } else {1181 ret = wait_event_interruptible_timeout(1182 qedi_ep->tcp_ofld_wait,1183 (qedi_ep->state !=1184 EP_STATE_DISCONN_START),1185 wait_delay);1186 if ((ret <= 0) || (qedi_ep->state == EP_STATE_DISCONN_START)) {1187 QEDI_WARN(&qedi->dbg_ctx,1188 "Destroy conn timedout or interrupted, ret=%d, delay=%d, cid=0x%x\n",1189 ret, wait_delay, qedi_ep->iscsi_cid);1190 }1191 }1192 1193ep_release_conn:1194 ret = qedi_ops->release_conn(qedi->cdev, qedi_ep->handle);1195 if (ret)1196 QEDI_WARN(&qedi->dbg_ctx,1197 "release_conn returned %d, cid=0x%x\n",1198 ret, qedi_ep->iscsi_cid);1199ep_exit_recover:1200 qedi_ep->state = EP_STATE_IDLE;1201 qedi->ep_tbl[qedi_ep->iscsi_cid] = NULL;1202 qedi->cid_que.conn_cid_tbl[qedi_ep->iscsi_cid] = NULL;1203 qedi_free_id(&qedi->lcl_port_tbl, qedi_ep->src_port);1204 qedi_free_sq(qedi, qedi_ep);1205 1206 if (qedi_conn)1207 qedi_conn->ep = NULL;1208 1209 qedi_ep->conn = NULL;1210 qedi_ep->qedi = NULL;1211 atomic_dec(&qedi->num_offloads);1212 1213 iscsi_destroy_endpoint(ep);1214}1215 1216static int qedi_data_avail(struct qedi_ctx *qedi, u16 vlanid)1217{1218 struct qed_dev *cdev = qedi->cdev;1219 struct qedi_uio_dev *udev;1220 struct qedi_uio_ctrl *uctrl;1221 struct sk_buff *skb;1222 u32 len;1223 int rc = 0;1224 1225 udev = qedi->udev;1226 if (!udev) {1227 QEDI_ERR(&qedi->dbg_ctx, "udev is NULL.\n");1228 return -EINVAL;1229 }1230 1231 uctrl = (struct qedi_uio_ctrl *)udev->uctrl;1232 if (!uctrl) {1233 QEDI_ERR(&qedi->dbg_ctx, "uctlr is NULL.\n");1234 return -EINVAL;1235 }1236 1237 len = uctrl->host_tx_pkt_len;1238 if (!len) {1239 QEDI_ERR(&qedi->dbg_ctx, "Invalid len %u\n", len);1240 return -EINVAL;1241 }1242 1243 skb = alloc_skb(len, GFP_ATOMIC);1244 if (!skb) {1245 QEDI_ERR(&qedi->dbg_ctx, "alloc_skb failed\n");1246 return -EINVAL;1247 }1248 1249 skb_put(skb, len);1250 memcpy(skb->data, udev->tx_pkt, len);1251 skb->ip_summed = CHECKSUM_NONE;1252 1253 if (vlanid)1254 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlanid);1255 1256 rc = qedi_ops->ll2->start_xmit(cdev, skb, 0);1257 if (rc) {1258 QEDI_ERR(&qedi->dbg_ctx, "ll2 start_xmit returned %d\n",1259 rc);1260 kfree_skb(skb);1261 }1262 1263 uctrl->host_tx_pkt_len = 0;1264 uctrl->hw_tx_cons++;1265 1266 return rc;1267}1268 1269static int qedi_set_path(struct Scsi_Host *shost, struct iscsi_path *path_data)1270{1271 struct qedi_ctx *qedi;1272 struct qedi_endpoint *qedi_ep;1273 int ret = 0;1274 u32 iscsi_cid;1275 u16 port_id = 0;1276 1277 if (!shost) {1278 ret = -ENXIO;1279 QEDI_ERR(NULL, "shost is NULL\n");1280 return ret;1281 }1282 1283 if (strcmp(shost->hostt->proc_name, "qedi")) {1284 ret = -ENXIO;1285 QEDI_ERR(NULL, "shost %s is invalid\n",1286 shost->hostt->proc_name);1287 return ret;1288 }1289 1290 qedi = iscsi_host_priv(shost);1291 if (path_data->handle == QEDI_PATH_HANDLE) {1292 ret = qedi_data_avail(qedi, path_data->vlan_id);1293 goto set_path_exit;1294 }1295 1296 iscsi_cid = (u32)path_data->handle;1297 if (iscsi_cid >= qedi->max_active_conns) {1298 ret = -EINVAL;1299 goto set_path_exit;1300 }1301 qedi_ep = qedi->ep_tbl[iscsi_cid];1302 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,1303 "iscsi_cid=0x%x, qedi_ep=%p\n", iscsi_cid, qedi_ep);1304 if (!qedi_ep) {1305 ret = -EINVAL;1306 goto set_path_exit;1307 }1308 1309 if (!is_valid_ether_addr(&path_data->mac_addr[0])) {1310 QEDI_NOTICE(&qedi->dbg_ctx, "dst mac NOT VALID\n");1311 qedi_ep->state = EP_STATE_OFLDCONN_NONE;1312 ret = -EIO;1313 goto set_path_exit;1314 }1315 1316 ether_addr_copy(&qedi_ep->src_mac[0], &qedi->mac[0]);1317 ether_addr_copy(&qedi_ep->dst_mac[0], &path_data->mac_addr[0]);1318 1319 qedi_ep->vlan_id = path_data->vlan_id;1320 if (path_data->pmtu < DEF_PATH_MTU) {1321 qedi_ep->pmtu = qedi->ll2_mtu;1322 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,1323 "MTU cannot be %u, using default MTU %u\n",1324 path_data->pmtu, qedi_ep->pmtu);1325 }1326 1327 if (path_data->pmtu != qedi->ll2_mtu) {1328 if (path_data->pmtu > JUMBO_MTU) {1329 ret = -EINVAL;1330 QEDI_ERR(NULL, "Invalid MTU %u\n", path_data->pmtu);1331 goto set_path_exit;1332 }1333 1334 qedi_reset_host_mtu(qedi, path_data->pmtu);1335 qedi_ep->pmtu = qedi->ll2_mtu;1336 }1337 1338 port_id = qedi_ep->src_port;1339 if (port_id >= QEDI_LOCAL_PORT_MIN &&1340 port_id < QEDI_LOCAL_PORT_MAX) {1341 if (qedi_alloc_id(&qedi->lcl_port_tbl, port_id))1342 port_id = 0;1343 } else {1344 port_id = 0;1345 }1346 1347 if (!port_id) {1348 port_id = qedi_alloc_new_id(&qedi->lcl_port_tbl);1349 if (port_id == QEDI_LOCAL_PORT_INVALID) {1350 QEDI_ERR(&qedi->dbg_ctx,1351 "Failed to allocate port id for iscsi_cid=0x%x\n",1352 iscsi_cid);1353 ret = -ENOMEM;1354 goto set_path_exit;1355 }1356 }1357 1358 qedi_ep->src_port = port_id;1359 1360 if (qedi_ep->ip_type == TCP_IPV4) {1361 memcpy(&qedi_ep->src_addr[0], &path_data->src.v4_addr,1362 sizeof(struct in_addr));1363 memcpy(&qedi->src_ip[0], &path_data->src.v4_addr,1364 sizeof(struct in_addr));1365 qedi->ip_type = TCP_IPV4;1366 1367 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,1368 "src addr:port=%pI4:%u, dst addr:port=%pI4:%u\n",1369 qedi_ep->src_addr, qedi_ep->src_port,1370 qedi_ep->dst_addr, qedi_ep->dst_port);1371 } else {1372 memcpy(&qedi_ep->src_addr[0], &path_data->src.v6_addr,1373 sizeof(struct in6_addr));1374 memcpy(&qedi->src_ip[0], &path_data->src.v6_addr,1375 sizeof(struct in6_addr));1376 qedi->ip_type = TCP_IPV6;1377 1378 QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,1379 "src addr:port=%pI6:%u, dst addr:port=%pI6:%u\n",1380 qedi_ep->src_addr, qedi_ep->src_port,1381 qedi_ep->dst_addr, qedi_ep->dst_port);1382 }1383 1384 queue_work(qedi->offload_thread, &qedi_ep->offload_work);1385 1386 ret = 0;1387 1388set_path_exit:1389 return ret;1390}1391 1392static umode_t qedi_attr_is_visible(int param_type, int param)1393{1394 switch (param_type) {1395 case ISCSI_HOST_PARAM:1396 switch (param) {1397 case ISCSI_HOST_PARAM_NETDEV_NAME:1398 case ISCSI_HOST_PARAM_HWADDRESS:1399 case ISCSI_HOST_PARAM_IPADDRESS:1400 return 0444;1401 default:1402 return 0;1403 }1404 case ISCSI_PARAM:1405 switch (param) {1406 case ISCSI_PARAM_MAX_RECV_DLENGTH:1407 case ISCSI_PARAM_MAX_XMIT_DLENGTH:1408 case ISCSI_PARAM_HDRDGST_EN:1409 case ISCSI_PARAM_DATADGST_EN:1410 case ISCSI_PARAM_CONN_ADDRESS:1411 case ISCSI_PARAM_CONN_PORT:1412 case ISCSI_PARAM_EXP_STATSN:1413 case ISCSI_PARAM_PERSISTENT_ADDRESS:1414 case ISCSI_PARAM_PERSISTENT_PORT:1415 case ISCSI_PARAM_PING_TMO:1416 case ISCSI_PARAM_RECV_TMO:1417 case ISCSI_PARAM_INITIAL_R2T_EN:1418 case ISCSI_PARAM_MAX_R2T:1419 case ISCSI_PARAM_IMM_DATA_EN:1420 case ISCSI_PARAM_FIRST_BURST:1421 case ISCSI_PARAM_MAX_BURST:1422 case ISCSI_PARAM_PDU_INORDER_EN:1423 case ISCSI_PARAM_DATASEQ_INORDER_EN:1424 case ISCSI_PARAM_ERL:1425 case ISCSI_PARAM_TARGET_NAME:1426 case ISCSI_PARAM_TPGT:1427 case ISCSI_PARAM_USERNAME:1428 case ISCSI_PARAM_PASSWORD:1429 case ISCSI_PARAM_USERNAME_IN:1430 case ISCSI_PARAM_PASSWORD_IN:1431 case ISCSI_PARAM_FAST_ABORT:1432 case ISCSI_PARAM_ABORT_TMO:1433 case ISCSI_PARAM_LU_RESET_TMO:1434 case ISCSI_PARAM_TGT_RESET_TMO:1435 case ISCSI_PARAM_IFACE_NAME:1436 case ISCSI_PARAM_INITIATOR_NAME:1437 case ISCSI_PARAM_BOOT_ROOT:1438 case ISCSI_PARAM_BOOT_NIC:1439 case ISCSI_PARAM_BOOT_TARGET:1440 return 0444;1441 default:1442 return 0;1443 }1444 }1445 1446 return 0;1447}1448 1449static void qedi_cleanup_task(struct iscsi_task *task)1450{1451 struct qedi_cmd *cmd;1452 1453 if (task->state == ISCSI_TASK_PENDING) {1454 QEDI_INFO(NULL, QEDI_LOG_IO, "Returning ref_cnt=%d\n",1455 refcount_read(&task->refcount));1456 return;1457 }1458 1459 if (task->sc)1460 qedi_iscsi_unmap_sg_list(task->dd_data);1461 1462 cmd = task->dd_data;1463 if (cmd->task_id != U16_MAX)1464 qedi_clear_task_idx(iscsi_host_priv(task->conn->session->host),1465 cmd->task_id);1466 1467 cmd->task_id = U16_MAX;1468 cmd->scsi_cmd = NULL;1469}1470 1471struct iscsi_transport qedi_iscsi_transport = {1472 .owner = THIS_MODULE,1473 .name = QEDI_MODULE_NAME,1474 .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_MULTI_R2T | CAP_DATADGST |1475 CAP_DATA_PATH_OFFLOAD | CAP_TEXT_NEGO,1476 .create_session = qedi_session_create,1477 .destroy_session = qedi_session_destroy,1478 .create_conn = qedi_conn_create,1479 .bind_conn = qedi_conn_bind,1480 .unbind_conn = iscsi_conn_unbind,1481 .start_conn = qedi_conn_start,1482 .stop_conn = iscsi_conn_stop,1483 .destroy_conn = qedi_conn_destroy,1484 .set_param = iscsi_set_param,1485 .get_ep_param = qedi_ep_get_param,1486 .get_conn_param = iscsi_conn_get_param,1487 .get_session_param = iscsi_session_get_param,1488 .get_host_param = qedi_host_get_param,1489 .send_pdu = iscsi_conn_send_pdu,1490 .get_stats = qedi_conn_get_stats,1491 .xmit_task = qedi_task_xmit,1492 .cleanup_task = qedi_cleanup_task,1493 .session_recovery_timedout = iscsi_session_recovery_timedout,1494 .ep_connect = qedi_ep_connect,1495 .ep_poll = qedi_ep_poll,1496 .ep_disconnect = qedi_ep_disconnect,1497 .set_path = qedi_set_path,1498 .attr_is_visible = qedi_attr_is_visible,1499};1500 1501void qedi_start_conn_recovery(struct qedi_ctx *qedi,1502 struct qedi_conn *qedi_conn)1503{1504 struct iscsi_cls_session *cls_sess;1505 struct iscsi_cls_conn *cls_conn;1506 struct iscsi_conn *conn;1507 1508 cls_conn = qedi_conn->cls_conn;1509 conn = cls_conn->dd_data;1510 cls_sess = iscsi_conn_to_session(cls_conn);1511 1512 if (iscsi_is_session_online(cls_sess)) {1513 qedi_conn->abrt_conn = 1;1514 QEDI_ERR(&qedi->dbg_ctx,1515 "Failing connection, state=0x%x, cid=0x%x\n",1516 conn->session->state, qedi_conn->iscsi_conn_id);1517 iscsi_conn_failure(qedi_conn->cls_conn->dd_data,1518 ISCSI_ERR_CONN_FAILED);1519 }1520}1521 1522static const struct {1523 enum iscsi_error_types error_code;1524 char *err_string;1525} qedi_iscsi_error[] = {1526 { ISCSI_STATUS_NONE,1527 "tcp_error none"1528 },1529 { ISCSI_CONN_ERROR_TASK_CID_MISMATCH,1530 "task cid mismatch"1531 },1532 { ISCSI_CONN_ERROR_TASK_NOT_VALID,1533 "invalid task"1534 },1535 { ISCSI_CONN_ERROR_RQ_RING_IS_FULL,1536 "rq ring full"1537 },1538 { ISCSI_CONN_ERROR_CMDQ_RING_IS_FULL,1539 "cmdq ring full"1540 },1541 { ISCSI_CONN_ERROR_HQE_CACHING_FAILED,1542 "sge caching failed"1543 },1544 { ISCSI_CONN_ERROR_HEADER_DIGEST_ERROR,1545 "hdr digest error"1546 },1547 { ISCSI_CONN_ERROR_LOCAL_COMPLETION_ERROR,1548 "local cmpl error"1549 },1550 { ISCSI_CONN_ERROR_DATA_OVERRUN,1551 "invalid task"1552 },1553 { ISCSI_CONN_ERROR_OUT_OF_SGES_ERROR,1554 "out of sge error"1555 },1556 { ISCSI_CONN_ERROR_TCP_IP_FRAGMENT_ERROR,1557 "tcp ip fragment error"1558 },1559 { ISCSI_CONN_ERROR_PROTOCOL_ERR_AHS_LEN,1560 "AHS len protocol error"1561 },1562 { ISCSI_CONN_ERROR_PROTOCOL_ERR_ITT_OUT_OF_RANGE,1563 "itt out of range error"1564 },1565 { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_EXCEEDS_PDU_SIZE,1566 "data seg more than pdu size"1567 },1568 { ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE,1569 "invalid opcode"1570 },1571 { ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE_BEFORE_UPDATE,1572 "invalid opcode before update"1573 },1574 { ISCSI_CONN_ERROR_UNVALID_NOPIN_DSL,1575 "unexpected opcode"1576 },1577 { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_CARRIES_NO_DATA,1578 "r2t carries no data"1579 },1580 { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SN,1581 "data sn error"1582 },1583 { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_IN_TTT,1584 "data TTT error"1585 },1586 { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_TTT,1587 "r2t TTT error"1588 },1589 { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_BUFFER_OFFSET,1590 "buffer offset error"1591 },1592 { ISCSI_CONN_ERROR_PROTOCOL_ERR_BUFFER_OFFSET_OOO,1593 "buffer offset ooo"1594 },1595 { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_SN,1596 "data seg len 0"1597 },1598 { ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0,1599 "data xer len error"1600 },1601 { ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1,1602 "data xer len1 error"1603 },1604 { ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_2,1605 "data xer len2 error"1606 },1607 { ISCSI_CONN_ERROR_PROTOCOL_ERR_LUN,1608 "protocol lun error"1609 },1610 { ISCSI_CONN_ERROR_PROTOCOL_ERR_F_BIT_ZERO,1611 "f bit zero error"1612 },1613 { ISCSI_CONN_ERROR_PROTOCOL_ERR_EXP_STAT_SN,1614 "exp stat sn error"1615 },1616 { ISCSI_CONN_ERROR_PROTOCOL_ERR_DSL_NOT_ZERO,1617 "dsl not zero error"1618 },1619 { ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_DSL,1620 "invalid dsl"1621 },1622 { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_TOO_BIG,1623 "data seg len too big"1624 },1625 { ISCSI_CONN_ERROR_PROTOCOL_ERR_OUTSTANDING_R2T_COUNT,1626 "outstanding r2t count error"1627 },1628 { ISCSI_CONN_ERROR_SENSE_DATA_LENGTH,1629 "sense datalen error"1630 },1631};1632 1633static char *qedi_get_iscsi_error(enum iscsi_error_types err_code)1634{1635 int i;1636 char *msg = NULL;1637 1638 for (i = 0; i < ARRAY_SIZE(qedi_iscsi_error); i++) {1639 if (qedi_iscsi_error[i].error_code == err_code) {1640 msg = qedi_iscsi_error[i].err_string;1641 break;1642 }1643 }1644 return msg;1645}1646 1647void qedi_process_iscsi_error(struct qedi_endpoint *ep,1648 struct iscsi_eqe_data *data)1649{1650 struct qedi_conn *qedi_conn;1651 struct qedi_ctx *qedi;1652 char warn_notice[] = "iscsi_warning";1653 char error_notice[] = "iscsi_error";1654 char unknown_msg[] = "Unknown error";1655 char *message;1656 int need_recovery = 0;1657 u32 err_mask = 0;1658 char *msg;1659 1660 if (!ep)1661 return;1662 1663 qedi_conn = ep->conn;1664 if (!qedi_conn)1665 return;1666 1667 qedi = ep->qedi;1668 1669 QEDI_ERR(&qedi->dbg_ctx, "async event iscsi error:0x%x\n",1670 data->error_code);1671 1672 if (err_mask) {1673 need_recovery = 0;1674 message = warn_notice;1675 } else {1676 need_recovery = 1;1677 message = error_notice;1678 }1679 1680 msg = qedi_get_iscsi_error(data->error_code);1681 if (!msg) {1682 need_recovery = 0;1683 msg = unknown_msg;1684 }1685 1686 iscsi_conn_printk(KERN_ALERT,1687 qedi_conn->cls_conn->dd_data,1688 "qedi: %s - %s\n", message, msg);1689 1690 if (need_recovery)1691 qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn);1692}1693 1694void qedi_process_tcp_error(struct qedi_endpoint *ep,1695 struct iscsi_eqe_data *data)1696{1697 struct qedi_conn *qedi_conn;1698 1699 if (!ep)1700 return;1701 1702 qedi_conn = ep->conn;1703 if (!qedi_conn)1704 return;1705 1706 QEDI_ERR(&ep->qedi->dbg_ctx, "async event TCP error:0x%x\n",1707 data->error_code);1708 1709 qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn);1710}1711