| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /******************************************************************************* |
|---|
| 2 | 3 | * This file contains tcm implementation using v4 configfs fabric infrastructure |
|---|
| 3 | 4 | * for QLogic target mode HBAs |
|---|
| .. | .. |
|---|
| 11 | 12 | * |
|---|
| 12 | 13 | * Copyright (c) 2010 Cisco Systems, Inc |
|---|
| 13 | 14 | * |
|---|
| 14 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 15 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 16 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 17 | | - * (at your option) any later version. |
|---|
| 18 | | - * |
|---|
| 19 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 20 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 21 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 22 | | - * GNU General Public License for more details. |
|---|
| 23 | 15 | ****************************************************************************/ |
|---|
| 24 | 16 | |
|---|
| 25 | 17 | |
|---|
| 26 | 18 | #include <linux/module.h> |
|---|
| 27 | | -#include <linux/moduleparam.h> |
|---|
| 28 | 19 | #include <linux/utsname.h> |
|---|
| 29 | 20 | #include <linux/vmalloc.h> |
|---|
| 30 | | -#include <linux/init.h> |
|---|
| 31 | 21 | #include <linux/list.h> |
|---|
| 32 | 22 | #include <linux/slab.h> |
|---|
| 33 | | -#include <linux/kthread.h> |
|---|
| 34 | 23 | #include <linux/types.h> |
|---|
| 35 | 24 | #include <linux/string.h> |
|---|
| 36 | 25 | #include <linux/configfs.h> |
|---|
| 37 | 26 | #include <linux/ctype.h> |
|---|
| 38 | 27 | #include <asm/unaligned.h> |
|---|
| 39 | | -#include <scsi/scsi.h> |
|---|
| 40 | 28 | #include <scsi/scsi_host.h> |
|---|
| 41 | | -#include <scsi/scsi_device.h> |
|---|
| 42 | | -#include <scsi/scsi_cmnd.h> |
|---|
| 43 | 29 | #include <target/target_core_base.h> |
|---|
| 44 | 30 | #include <target/target_core_fabric.h> |
|---|
| 45 | 31 | |
|---|
| .. | .. |
|---|
| 108 | 94 | b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); |
|---|
| 109 | 95 | } |
|---|
| 110 | 96 | |
|---|
| 111 | | -static char *tcm_qla2xxx_get_fabric_name(void) |
|---|
| 112 | | -{ |
|---|
| 113 | | - return "qla2xxx"; |
|---|
| 114 | | -} |
|---|
| 115 | | - |
|---|
| 116 | 97 | /* |
|---|
| 117 | 98 | * From drivers/scsi/scsi_transport_fc.c:fc_parse_wwn |
|---|
| 118 | 99 | */ |
|---|
| .. | .. |
|---|
| 176 | 157 | return rc; |
|---|
| 177 | 158 | |
|---|
| 178 | 159 | return 0; |
|---|
| 179 | | -} |
|---|
| 180 | | - |
|---|
| 181 | | -static char *tcm_qla2xxx_npiv_get_fabric_name(void) |
|---|
| 182 | | -{ |
|---|
| 183 | | - return "qla2xxx_npiv"; |
|---|
| 184 | 160 | } |
|---|
| 185 | 161 | |
|---|
| 186 | 162 | static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg) |
|---|
| .. | .. |
|---|
| 270 | 246 | */ |
|---|
| 271 | 247 | static void tcm_qla2xxx_free_mcmd(struct qla_tgt_mgmt_cmd *mcmd) |
|---|
| 272 | 248 | { |
|---|
| 249 | + if (!mcmd) |
|---|
| 250 | + return; |
|---|
| 273 | 251 | INIT_WORK(&mcmd->free_work, tcm_qla2xxx_complete_mcmd); |
|---|
| 274 | 252 | queue_work(tcm_qla2xxx_free_wq, &mcmd->free_work); |
|---|
| 275 | 253 | } |
|---|
| .. | .. |
|---|
| 282 | 260 | |
|---|
| 283 | 261 | WARN_ON(cmd->trc_flags & TRC_CMD_FREE); |
|---|
| 284 | 262 | |
|---|
| 263 | + /* To do: protect all tgt_counters manipulations with proper locking. */ |
|---|
| 285 | 264 | cmd->qpair->tgt_counters.qla_core_ret_sta_ctio++; |
|---|
| 286 | 265 | cmd->trc_flags |= TRC_CMD_FREE; |
|---|
| 266 | + cmd->cmd_sent_to_fw = 0; |
|---|
| 267 | + |
|---|
| 287 | 268 | transport_generic_free_cmd(&cmd->se_cmd, 0); |
|---|
| 269 | +} |
|---|
| 270 | + |
|---|
| 271 | +static struct qla_tgt_cmd *tcm_qla2xxx_get_cmd(struct fc_port *sess) |
|---|
| 272 | +{ |
|---|
| 273 | + struct se_session *se_sess = sess->se_sess; |
|---|
| 274 | + struct qla_tgt_cmd *cmd; |
|---|
| 275 | + int tag, cpu; |
|---|
| 276 | + |
|---|
| 277 | + tag = sbitmap_queue_get(&se_sess->sess_tag_pool, &cpu); |
|---|
| 278 | + if (tag < 0) |
|---|
| 279 | + return NULL; |
|---|
| 280 | + |
|---|
| 281 | + cmd = &((struct qla_tgt_cmd *)se_sess->sess_cmd_map)[tag]; |
|---|
| 282 | + memset(cmd, 0, sizeof(struct qla_tgt_cmd)); |
|---|
| 283 | + cmd->se_cmd.map_tag = tag; |
|---|
| 284 | + cmd->se_cmd.map_cpu = cpu; |
|---|
| 285 | + |
|---|
| 286 | + return cmd; |
|---|
| 287 | +} |
|---|
| 288 | + |
|---|
| 289 | +static void tcm_qla2xxx_rel_cmd(struct qla_tgt_cmd *cmd) |
|---|
| 290 | +{ |
|---|
| 291 | + target_free_tag(cmd->sess->se_sess, &cmd->se_cmd); |
|---|
| 288 | 292 | } |
|---|
| 289 | 293 | |
|---|
| 290 | 294 | /* |
|---|
| .. | .. |
|---|
| 332 | 336 | qlt_free_mcmd(mcmd); |
|---|
| 333 | 337 | return; |
|---|
| 334 | 338 | } |
|---|
| 335 | | - |
|---|
| 336 | 339 | cmd = container_of(se_cmd, struct qla_tgt_cmd, se_cmd); |
|---|
| 340 | + |
|---|
| 341 | + if (WARN_ON(cmd->cmd_sent_to_fw)) |
|---|
| 342 | + return; |
|---|
| 343 | + |
|---|
| 337 | 344 | qlt_free_cmd(cmd); |
|---|
| 338 | 345 | } |
|---|
| 339 | 346 | |
|---|
| .. | .. |
|---|
| 366 | 373 | target_sess_cmd_list_set_waiting(se_sess); |
|---|
| 367 | 374 | spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); |
|---|
| 368 | 375 | |
|---|
| 376 | + sess->explicit_logout = 1; |
|---|
| 369 | 377 | tcm_qla2xxx_put_sess(sess); |
|---|
| 370 | 378 | } |
|---|
| 371 | 379 | |
|---|
| .. | .. |
|---|
| 407 | 415 | se_cmd->pi_err = 0; |
|---|
| 408 | 416 | |
|---|
| 409 | 417 | /* |
|---|
| 410 | | - * qla_target.c:qlt_rdy_to_xfer() will call pci_map_sg() to setup |
|---|
| 418 | + * qla_target.c:qlt_rdy_to_xfer() will call dma_map_sg() to setup |
|---|
| 411 | 419 | * the SGL mappings into PCIe memory for incoming FCP WRITE data. |
|---|
| 412 | 420 | */ |
|---|
| 413 | 421 | return qlt_rdy_to_xfer(cmd); |
|---|
| 414 | | -} |
|---|
| 415 | | - |
|---|
| 416 | | -static int tcm_qla2xxx_write_pending_status(struct se_cmd *se_cmd) |
|---|
| 417 | | -{ |
|---|
| 418 | | - unsigned long flags; |
|---|
| 419 | | - /* |
|---|
| 420 | | - * Check for WRITE_PENDING status to determine if we need to wait for |
|---|
| 421 | | - * CTIO aborts to be posted via hardware in tcm_qla2xxx_handle_data(). |
|---|
| 422 | | - */ |
|---|
| 423 | | - spin_lock_irqsave(&se_cmd->t_state_lock, flags); |
|---|
| 424 | | - if (se_cmd->t_state == TRANSPORT_WRITE_PENDING || |
|---|
| 425 | | - se_cmd->t_state == TRANSPORT_COMPLETE_QF_WP) { |
|---|
| 426 | | - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); |
|---|
| 427 | | - wait_for_completion_timeout(&se_cmd->t_transport_stop_comp, |
|---|
| 428 | | - 50); |
|---|
| 429 | | - return 0; |
|---|
| 430 | | - } |
|---|
| 431 | | - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); |
|---|
| 432 | | - |
|---|
| 433 | | - return 0; |
|---|
| 434 | 422 | } |
|---|
| 435 | 423 | |
|---|
| 436 | 424 | static void tcm_qla2xxx_set_default_node_attrs(struct se_node_acl *nacl) |
|---|
| .. | .. |
|---|
| 507 | 495 | * Otherwise return an exception via CHECK_CONDITION status. |
|---|
| 508 | 496 | */ |
|---|
| 509 | 497 | cmd->cmd_in_wq = 0; |
|---|
| 498 | + cmd->cmd_sent_to_fw = 0; |
|---|
| 499 | + if (cmd->aborted) { |
|---|
| 500 | + transport_generic_request_failure(&cmd->se_cmd, |
|---|
| 501 | + TCM_CHECK_CONDITION_ABORT_CMD); |
|---|
| 502 | + return; |
|---|
| 503 | + } |
|---|
| 510 | 504 | |
|---|
| 511 | 505 | cmd->qpair->tgt_counters.qla_core_ret_ctio++; |
|---|
| 512 | 506 | if (!cmd->write_data_transferred) { |
|---|
| 513 | | - /* |
|---|
| 514 | | - * Check if se_cmd has already been aborted via LUN_RESET, and |
|---|
| 515 | | - * waiting upon completion in tcm_qla2xxx_write_pending_status() |
|---|
| 516 | | - */ |
|---|
| 517 | | - if (cmd->se_cmd.transport_state & CMD_T_ABORTED) { |
|---|
| 518 | | - complete(&cmd->se_cmd.t_transport_stop_comp); |
|---|
| 519 | | - return; |
|---|
| 520 | | - } |
|---|
| 521 | | - |
|---|
| 522 | 507 | switch (cmd->dif_err_code) { |
|---|
| 523 | 508 | case DIF_ERR_GRD: |
|---|
| 524 | 509 | cmd->se_cmd.pi_err = |
|---|
| .. | .. |
|---|
| 861 | 846 | struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, \ |
|---|
| 862 | 847 | struct tcm_qla2xxx_tpg, se_tpg); \ |
|---|
| 863 | 848 | \ |
|---|
| 864 | | - return sprintf(page, "%u\n", tpg->tpg_attrib.name); \ |
|---|
| 849 | + return sprintf(page, "%d\n", tpg->tpg_attrib.name); \ |
|---|
| 865 | 850 | } \ |
|---|
| 866 | 851 | \ |
|---|
| 867 | 852 | static ssize_t tcm_qla2xxx_tpg_attrib_##name##_store( \ |
|---|
| .. | .. |
|---|
| 1179 | 1164 | /* |
|---|
| 1180 | 1165 | * Expected to be called with struct qla_hw_data->tgt.sess_lock held |
|---|
| 1181 | 1166 | */ |
|---|
| 1182 | | -static struct fc_port *tcm_qla2xxx_find_sess_by_s_id( |
|---|
| 1183 | | - scsi_qla_host_t *vha, |
|---|
| 1184 | | - const uint8_t *s_id) |
|---|
| 1167 | +static struct fc_port *tcm_qla2xxx_find_sess_by_s_id(scsi_qla_host_t *vha, |
|---|
| 1168 | + const be_id_t s_id) |
|---|
| 1185 | 1169 | { |
|---|
| 1186 | 1170 | struct tcm_qla2xxx_lport *lport; |
|---|
| 1187 | 1171 | struct se_node_acl *se_nacl; |
|---|
| .. | .. |
|---|
| 1224 | 1208 | struct tcm_qla2xxx_nacl *nacl, |
|---|
| 1225 | 1209 | struct se_session *se_sess, |
|---|
| 1226 | 1210 | struct fc_port *fc_port, |
|---|
| 1227 | | - uint8_t *s_id) |
|---|
| 1211 | + be_id_t s_id) |
|---|
| 1228 | 1212 | { |
|---|
| 1229 | 1213 | u32 key; |
|---|
| 1230 | 1214 | void *slot; |
|---|
| .. | .. |
|---|
| 1391 | 1375 | struct tcm_qla2xxx_nacl *nacl, struct fc_port *sess) |
|---|
| 1392 | 1376 | { |
|---|
| 1393 | 1377 | struct se_session *se_sess = sess->se_sess; |
|---|
| 1394 | | - unsigned char be_sid[3]; |
|---|
| 1395 | | - |
|---|
| 1396 | | - be_sid[0] = sess->d_id.b.domain; |
|---|
| 1397 | | - be_sid[1] = sess->d_id.b.area; |
|---|
| 1398 | | - be_sid[2] = sess->d_id.b.al_pa; |
|---|
| 1399 | 1378 | |
|---|
| 1400 | 1379 | tcm_qla2xxx_set_sess_by_s_id(lport, NULL, nacl, se_sess, |
|---|
| 1401 | | - sess, be_sid); |
|---|
| 1380 | + sess, port_id_to_be_id(sess->d_id)); |
|---|
| 1402 | 1381 | tcm_qla2xxx_set_sess_by_loop_id(lport, NULL, nacl, se_sess, |
|---|
| 1403 | 1382 | sess, sess->loop_id); |
|---|
| 1404 | 1383 | } |
|---|
| .. | .. |
|---|
| 1444 | 1423 | struct fc_port *qlat_sess = p; |
|---|
| 1445 | 1424 | uint16_t loop_id = qlat_sess->loop_id; |
|---|
| 1446 | 1425 | unsigned long flags; |
|---|
| 1447 | | - unsigned char be_sid[3]; |
|---|
| 1448 | | - |
|---|
| 1449 | | - be_sid[0] = qlat_sess->d_id.b.domain; |
|---|
| 1450 | | - be_sid[1] = qlat_sess->d_id.b.area; |
|---|
| 1451 | | - be_sid[2] = qlat_sess->d_id.b.al_pa; |
|---|
| 1452 | 1426 | |
|---|
| 1453 | 1427 | /* |
|---|
| 1454 | 1428 | * And now setup se_nacl and session pointers into HW lport internal |
|---|
| 1455 | 1429 | * mappings for fabric S_ID and LOOP_ID. |
|---|
| 1456 | 1430 | */ |
|---|
| 1457 | 1431 | spin_lock_irqsave(&ha->tgt.sess_lock, flags); |
|---|
| 1458 | | - tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, |
|---|
| 1459 | | - se_sess, qlat_sess, be_sid); |
|---|
| 1432 | + tcm_qla2xxx_set_sess_by_s_id(lport, se_nacl, nacl, se_sess, qlat_sess, |
|---|
| 1433 | + port_id_to_be_id(qlat_sess->d_id)); |
|---|
| 1460 | 1434 | tcm_qla2xxx_set_sess_by_loop_id(lport, se_nacl, nacl, |
|---|
| 1461 | 1435 | se_sess, qlat_sess, loop_id); |
|---|
| 1462 | 1436 | spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); |
|---|
| .. | .. |
|---|
| 1492 | 1466 | */ |
|---|
| 1493 | 1467 | tpg = lport->tpg_1; |
|---|
| 1494 | 1468 | if (!tpg) { |
|---|
| 1495 | | - pr_err("Unable to lcoate struct tcm_qla2xxx_lport->tpg_1\n"); |
|---|
| 1469 | + pr_err("Unable to locate struct tcm_qla2xxx_lport->tpg_1\n"); |
|---|
| 1496 | 1470 | return -EINVAL; |
|---|
| 1497 | 1471 | } |
|---|
| 1498 | 1472 | /* |
|---|
| .. | .. |
|---|
| 1596 | 1570 | .handle_cmd = tcm_qla2xxx_handle_cmd, |
|---|
| 1597 | 1571 | .handle_data = tcm_qla2xxx_handle_data, |
|---|
| 1598 | 1572 | .handle_tmr = tcm_qla2xxx_handle_tmr, |
|---|
| 1573 | + .get_cmd = tcm_qla2xxx_get_cmd, |
|---|
| 1574 | + .rel_cmd = tcm_qla2xxx_rel_cmd, |
|---|
| 1599 | 1575 | .free_cmd = tcm_qla2xxx_free_cmd, |
|---|
| 1600 | 1576 | .free_mcmd = tcm_qla2xxx_free_mcmd, |
|---|
| 1601 | 1577 | .free_session = tcm_qla2xxx_free_session, |
|---|
| .. | .. |
|---|
| 1852 | 1828 | |
|---|
| 1853 | 1829 | static const struct target_core_fabric_ops tcm_qla2xxx_ops = { |
|---|
| 1854 | 1830 | .module = THIS_MODULE, |
|---|
| 1855 | | - .name = "qla2xxx", |
|---|
| 1831 | + .fabric_name = "qla2xxx", |
|---|
| 1856 | 1832 | .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), |
|---|
| 1857 | 1833 | /* |
|---|
| 1858 | 1834 | * XXX: Limit assumes single page per scatter-gather-list entry. |
|---|
| 1859 | 1835 | * Current maximum is ~4.9 MB per se_cmd->t_data_sg with PAGE_SIZE=4096 |
|---|
| 1860 | 1836 | */ |
|---|
| 1861 | 1837 | .max_data_sg_nents = 1200, |
|---|
| 1862 | | - .get_fabric_name = tcm_qla2xxx_get_fabric_name, |
|---|
| 1863 | 1838 | .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, |
|---|
| 1864 | 1839 | .tpg_get_tag = tcm_qla2xxx_get_tag, |
|---|
| 1865 | 1840 | .tpg_check_demo_mode = tcm_qla2xxx_check_demo_mode, |
|---|
| .. | .. |
|---|
| 1877 | 1852 | .sess_get_index = tcm_qla2xxx_sess_get_index, |
|---|
| 1878 | 1853 | .sess_get_initiator_sid = NULL, |
|---|
| 1879 | 1854 | .write_pending = tcm_qla2xxx_write_pending, |
|---|
| 1880 | | - .write_pending_status = tcm_qla2xxx_write_pending_status, |
|---|
| 1881 | 1855 | .set_default_node_attributes = tcm_qla2xxx_set_default_node_attrs, |
|---|
| 1882 | 1856 | .get_cmd_state = tcm_qla2xxx_get_cmd_state, |
|---|
| 1883 | 1857 | .queue_data_in = tcm_qla2xxx_queue_data_in, |
|---|
| .. | .. |
|---|
| 1901 | 1875 | |
|---|
| 1902 | 1876 | static const struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { |
|---|
| 1903 | 1877 | .module = THIS_MODULE, |
|---|
| 1904 | | - .name = "qla2xxx_npiv", |
|---|
| 1878 | + .fabric_name = "qla2xxx_npiv", |
|---|
| 1905 | 1879 | .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), |
|---|
| 1906 | | - .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, |
|---|
| 1907 | 1880 | .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, |
|---|
| 1908 | 1881 | .tpg_get_tag = tcm_qla2xxx_get_tag, |
|---|
| 1909 | 1882 | .tpg_check_demo_mode = tcm_qla2xxx_check_demo_mode, |
|---|
| .. | .. |
|---|
| 1919 | 1892 | .sess_get_index = tcm_qla2xxx_sess_get_index, |
|---|
| 1920 | 1893 | .sess_get_initiator_sid = NULL, |
|---|
| 1921 | 1894 | .write_pending = tcm_qla2xxx_write_pending, |
|---|
| 1922 | | - .write_pending_status = tcm_qla2xxx_write_pending_status, |
|---|
| 1923 | 1895 | .set_default_node_attributes = tcm_qla2xxx_set_default_node_attrs, |
|---|
| 1924 | 1896 | .get_cmd_state = tcm_qla2xxx_get_cmd_state, |
|---|
| 1925 | 1897 | .queue_data_in = tcm_qla2xxx_queue_data_in, |
|---|
| .. | .. |
|---|
| 1984 | 1956 | { |
|---|
| 1985 | 1957 | int ret; |
|---|
| 1986 | 1958 | |
|---|
| 1959 | + BUILD_BUG_ON(sizeof(struct abts_recv_from_24xx) != 64); |
|---|
| 1960 | + BUILD_BUG_ON(sizeof(struct abts_resp_from_24xx_fw) != 64); |
|---|
| 1961 | + BUILD_BUG_ON(sizeof(struct atio7_fcp_cmnd) != 32); |
|---|
| 1962 | + BUILD_BUG_ON(sizeof(struct atio_from_isp) != 64); |
|---|
| 1963 | + BUILD_BUG_ON(sizeof(struct ba_acc_le) != 12); |
|---|
| 1964 | + BUILD_BUG_ON(sizeof(struct ba_rjt_le) != 4); |
|---|
| 1965 | + BUILD_BUG_ON(sizeof(struct ctio7_from_24xx) != 64); |
|---|
| 1966 | + BUILD_BUG_ON(sizeof(struct ctio7_to_24xx) != 64); |
|---|
| 1967 | + BUILD_BUG_ON(sizeof(struct ctio_crc2_to_fw) != 64); |
|---|
| 1968 | + BUILD_BUG_ON(sizeof(struct ctio_crc_from_fw) != 64); |
|---|
| 1969 | + BUILD_BUG_ON(sizeof(struct ctio_to_2xxx) != 64); |
|---|
| 1970 | + BUILD_BUG_ON(sizeof(struct fcp_hdr) != 24); |
|---|
| 1971 | + BUILD_BUG_ON(sizeof(struct fcp_hdr_le) != 24); |
|---|
| 1972 | + BUILD_BUG_ON(sizeof(struct nack_to_isp) != 64); |
|---|
| 1973 | + |
|---|
| 1987 | 1974 | ret = tcm_qla2xxx_register_configfs(); |
|---|
| 1988 | 1975 | if (ret < 0) |
|---|
| 1989 | 1976 | return ret; |
|---|