Commit 2d70c103 authored by Nicholas Bellinger's avatar Nicholas Bellinger Committed by James Bottomley

[SCSI] qla2xxx: Add LLD target-mode infrastructure for >= 24xx series

Add LLD target mode for >= 24xx series HW.  This code was originally based on
external qla2x00t module based on 8.02.01-k4, and has been refactored to
push the bulk of code into mainline qla2xxx.ko LLD -> qla_target.c.

The implementation uses internal workqueues for I/O context submission
into tcm_qla2xxx code, and includes the struct qla_tgt_func_tmpl API for
external interaction to allow qla2xxx LDD to function without direct
target-core dependencies:

It also enables qla_target.c usage within existing qla2xxx LLD code.
This includes:

*) Addition of target mode specific members to existing data
structures in qla_def.h and struct qla_hw_data->tgt_ops using
qla_target.h:struct qla_tgt_func_tmpl

*) Addition of struct qla_tgt_func_tmpl and direct calls into
qla_target.c logic w/ qlt_* prefixed functions.

*) Addition of qla_iocb.c:qla2x00_req_pkt() for ring processing, and
qla2x00_issue_marker() for handling request/response queue processing
for target mode operation

*) Addition of various qla_tgt_mode_enabled() logic checks in
qla24xx_nvram_config(), qla2x00_initialize_adapter(), qla2x00_rff_id(),
qla2x00_abort_isp(), qla24xx_modify_vp_config(), and
qla2x00_vp_abort_isp().

By default the new qlini_mode module parameter is setting initiator-mode
to 'enabled' in order for 'modprobe qla2xxx' to continue to function as
expected in initiator only mode.  Enabling target-mode operation will
currently require a:

    modprobe qla2xxx qlini_mode="disabled"

in order to explictly disabled initiator mode and allow target-mode
to be enabled via tcm_qla2xxx configfs fabric callers.

(nab: Convert to qlini_mode='enabled' by default in qla_target.c)
(joern: Remove loop_id from qla_tgt_make_local_sess() arguments +
        Remove unused s_id + fix s_id endianness bug +
        simplify qla_tgt_abort_work)
(gerard: fix section __exit mismatch in qla_tgt_exit)
(arun: Capture ATIO queue during firmware dump + Send SCR in target mode +
       Target mode review comments)
(roland: Don't create duplicate target sessions to address tearing down
         ACLs with IO in flight + Add missing call to qlt_fc_port_deleted
	 call during qla2x00_schedule_rport_del timeout)
Signed-off-by: default avatarNicholas A. Bellinger <nab@linux-iscsi.org>
Signed-off-by: default avatarChad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 2c1391d3
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \
qla_nx.o
qla_nx.o qla_target.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o
......@@ -5,6 +5,7 @@
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include "qla_def.h"
#include "qla_target.h"
#include <linux/kthread.h>
#include <linux/vmalloc.h>
......@@ -1737,6 +1738,7 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
fc_host_supported_speeds(vha->host) =
fc_host_supported_speeds(base_vha->host);
qlt_vport_create(vha, ha);
qla24xx_vport_disable(fc_vport, disable);
if (ha->flags.cpu_affinity_enabled) {
......@@ -1951,7 +1953,8 @@ qla2x00_init_host_attr(scsi_qla_host_t *vha)
fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count;
fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
fc_host_supported_classes(vha->host) = FC_COS_CLASS3;
fc_host_supported_classes(vha->host) = ha->tgt.enable_class_2 ?
(FC_COS_CLASS2|FC_COS_CLASS3) : FC_COS_CLASS3;
fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports;
fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count;
......
......@@ -11,8 +11,8 @@
* ----------------------------------------------------------------------
* | Level | Last Value Used | Holes |
* ----------------------------------------------------------------------
* | Module Init and Probe | 0x0120 | 0x4b,0xba,0xfa |
* | Mailbox commands | 0x113e | 0x111a-0x111b |
* | Module Init and Probe | 0x0122 | 0x4b,0xba,0xfa |
* | Mailbox commands | 0x1140 | 0x111a-0x111b |
* | | | 0x112c-0x112e |
* | | | 0x113a |
* | Device Discovery | 0x2086 | 0x2020-0x2022 |
......@@ -33,6 +33,9 @@
* | ISP82XX Specific | 0xb054 | 0xb024 |
* | MultiQ | 0xc00c | |
* | Misc | 0xd010 | |
* | Target Mode | 0xe06f | |
* | Target Mode Management | 0xf071 | |
* | Target Mode Task Management | 0x1000b | |
* ----------------------------------------------------------------------
*/
......@@ -379,6 +382,54 @@ qla25xx_copy_fce(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
return (char *)iter_reg + ntohl(fcec->size);
}
static inline void *
qla2xxx_copy_atioqueues(struct qla_hw_data *ha, void *ptr,
uint32_t **last_chain)
{
struct qla2xxx_mqueue_chain *q;
struct qla2xxx_mqueue_header *qh;
uint32_t num_queues;
int que;
struct {
int length;
void *ring;
} aq, *aqp;
if (!ha->tgt.atio_q_length)
return ptr;
num_queues = 1;
aqp = &aq;
aqp->length = ha->tgt.atio_q_length;
aqp->ring = ha->tgt.atio_ring;
for (que = 0; que < num_queues; que++) {
/* aqp = ha->atio_q_map[que]; */
q = ptr;
*last_chain = &q->type;
q->type = __constant_htonl(DUMP_CHAIN_QUEUE);
q->chain_size = htonl(
sizeof(struct qla2xxx_mqueue_chain) +
sizeof(struct qla2xxx_mqueue_header) +
(aqp->length * sizeof(request_t)));
ptr += sizeof(struct qla2xxx_mqueue_chain);
/* Add header. */
qh = ptr;
qh->queue = __constant_htonl(TYPE_ATIO_QUEUE);
qh->number = htonl(que);
qh->size = htonl(aqp->length * sizeof(request_t));
ptr += sizeof(struct qla2xxx_mqueue_header);
/* Add data. */
memcpy(ptr, aqp->ring, aqp->length * sizeof(request_t));
ptr += aqp->length * sizeof(request_t);
}
return ptr;
}
static inline void *
qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain)
{
......@@ -874,6 +925,8 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
struct qla24xx_fw_dump *fw;
uint32_t ext_mem_cnt;
void *nxt;
void *nxt_chain;
uint32_t *last_chain = NULL;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
if (IS_QLA82XX(ha))
......@@ -1092,6 +1145,16 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
qla24xx_copy_eft(ha, nxt);
nxt_chain = (void *)ha->fw_dump + ha->chain_offset;
nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain);
if (last_chain) {
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
}
/* Adjust valid length. */
ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump);
qla24xx_fw_dump_failed_0:
qla2xxx_dump_post_process(base_vha, rval);
......@@ -1400,6 +1463,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Chain entries -- started with MQ. */
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain);
nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain);
if (last_chain) {
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
......@@ -1718,6 +1782,7 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Chain entries -- started with MQ. */
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain);
nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain);
if (last_chain) {
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
......@@ -2219,6 +2284,7 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
/* Chain entries -- started with MQ. */
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain);
nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain);
if (last_chain) {
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
......
......@@ -244,6 +244,7 @@ struct qla2xxx_mqueue_header {
uint32_t queue;
#define TYPE_REQUEST_QUEUE 0x1
#define TYPE_RESPONSE_QUEUE 0x2
#define TYPE_ATIO_QUEUE 0x3
uint32_t number;
uint32_t size;
};
......@@ -344,3 +345,6 @@ ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...);
* more verbosity is required. It might not
* be applicable to all the levels.
*/
#define ql_dbg_tgt 0x00004000 /* Target mode */
#define ql_dbg_tgt_mgt 0x00002000 /* Target mode management */
#define ql_dbg_tgt_tmr 0x00001000 /* Target mode task management */
......@@ -186,6 +186,7 @@
#define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/
#define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */
struct req_que;
......@@ -1234,11 +1235,27 @@ typedef struct {
* ISP queue - response queue entry definition.
*/
typedef struct {
uint8_t data[60];
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System defined handle */
uint8_t data[52];
uint32_t signature;
#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */
} response_t;
/*
* ISP queue - ATIO queue entry definition.
*/
struct atio {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t data[58];
uint32_t signature;
#define ATIO_PROCESSED 0xDEADDEAD /* Signature */
};
typedef union {
uint16_t extended;
struct {
......@@ -1749,6 +1766,7 @@ static const char * const port_state_str[] = {
#define FCF_LOGIN_NEEDED BIT_1
#define FCF_FCP2_DEVICE BIT_2
#define FCF_ASYNC_SENT BIT_3
#define FCF_CONF_COMP_SUPPORTED BIT_4
/* No loop ID flag. */
#define FC_NO_LOOP_ID 0x1000
......@@ -2421,6 +2439,40 @@ struct qlfc_fw {
uint32_t len;
};
struct qlt_hw_data {
/* Protected by hw lock */
uint32_t enable_class_2:1;
uint32_t enable_explicit_conf:1;
uint32_t ini_mode_force_reverse:1;
uint32_t node_name_set:1;
dma_addr_t atio_dma; /* Physical address. */
struct atio *atio_ring; /* Base virtual address */
struct atio *atio_ring_ptr; /* Current address. */
uint16_t atio_ring_index; /* Current index. */
uint16_t atio_q_length;
void *target_lport_ptr;
struct qla_tgt_func_tmpl *tgt_ops;
struct qla_tgt *qla_tgt;
struct qla_tgt_cmd *cmds[MAX_OUTSTANDING_COMMANDS];
uint16_t current_handle;
struct qla_tgt_vp_map *tgt_vp_map;
struct mutex tgt_mutex;
struct mutex tgt_host_action_mutex;
int saved_set;
uint16_t saved_exchange_count;
uint32_t saved_firmware_options_1;
uint32_t saved_firmware_options_2;
uint32_t saved_firmware_options_3;
uint8_t saved_firmware_options[2];
uint8_t saved_add_firmware_options[2];
uint8_t tgt_node_name[WWN_SIZE];
};
/*
* Qlogic host adapter specific data structure.
*/
......@@ -2463,7 +2515,8 @@ struct qla_hw_data {
uint32_t isp82xx_reset_hdlr_active:1;
uint32_t isp82xx_reset_owner:1;
uint32_t isp82xx_no_md_cap:1;
/* 28 bits */
uint32_t host_shutting_down:1;
/* 30 bits */
} flags;
/* This spinlock is used to protect "io transactions", you must
......@@ -2864,6 +2917,8 @@ struct qla_hw_data {
dma_addr_t md_tmplt_hdr_dma;
void *md_dump;
uint32_t md_dump_size;
struct qlt_hw_data tgt;
};
/*
......@@ -2921,6 +2976,7 @@ typedef struct scsi_qla_host {
#define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */
#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */
#define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */
#define SCR_PENDING 21 /* SCR in target mode */
uint32_t device_flags;
#define SWITCH_FOUND BIT_0
......@@ -2986,6 +3042,15 @@ typedef struct scsi_qla_host {
atomic_t vref_count;
} scsi_qla_host_t;
#define SET_VP_IDX 1
#define SET_AL_PA 2
#define RESET_VP_IDX 3
#define RESET_AL_PA 4
struct qla_tgt_vp_map {
uint8_t idx;
scsi_qla_host_t *vha;
};
/*
* Macros to help code, maintain, etc.
*/
......
......@@ -175,6 +175,7 @@ extern int qla2x00_vp_abort_isp(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_iocb.c source file.
*/
extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
extern uint16_t qla2x00_calc_iocbs_64(uint16_t);
extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t);
......@@ -188,6 +189,8 @@ extern uint16_t qla24xx_calc_iocbs(scsi_qla_host_t *, uint16_t);
extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t);
extern int qla24xx_dif_start_scsi(srb_t *);
extern void *qla2x00_alloc_iocbs(scsi_qla_host_t *, srb_t *);
extern int qla2x00_issue_marker(scsi_qla_host_t *, int);
/*
* Global Function Prototypes in qla_mbx.c source file.
......@@ -238,6 +241,9 @@ qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t *);
extern int
qla2x00_init_firmware(scsi_qla_host_t *, uint16_t);
extern int
qla2x00_get_node_name_list(scsi_qla_host_t *, void **, int *);
extern int
qla2x00_get_port_database(scsi_qla_host_t *, fc_port_t *, uint8_t);
......@@ -548,6 +554,7 @@ extern void qla2x00_sp_free(void *, void *);
extern void qla2x00_sp_timeout(unsigned long);
extern void qla2x00_bsg_job_done(void *, void *, int);
extern void qla2x00_bsg_sp_free(void *, void *);
extern void qla2x00_start_iocbs(struct scsi_qla_host *, struct req_que *);
/* Interrupt related */
extern irqreturn_t qla82xx_intr_handler(int, void *);
......
......@@ -5,6 +5,7 @@
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include "qla_def.h"
#include "qla_target.h"
static int qla2x00_sns_ga_nxt(scsi_qla_host_t *, fc_port_t *);
static int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_t *);
......@@ -556,7 +557,8 @@ qla2x00_rff_id(scsi_qla_host_t *vha)
ct_req->req.rff_id.port_id[1] = vha->d_id.b.area;
ct_req->req.rff_id.port_id[2] = vha->d_id.b.al_pa;
ct_req->req.rff_id.fc4_feature = BIT_1;
qlt_rff_id(vha, ct_req);
ct_req->req.rff_id.fc4_type = 0x08; /* SCSI - FCP */
/* Execute MS IOCB */
......
......@@ -17,6 +17,9 @@
#include <asm/prom.h>
#endif
#include <target/target_core_base.h>
#include "qla_target.h"
/*
* QLogic ISP2x00 Hardware Support Function Prototypes.
*/
......@@ -518,7 +521,10 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
return QLA_FUNCTION_FAILED;
}
}
rval = qla2x00_init_rings(vha);
if (qla_ini_mode_enabled(vha))
rval = qla2x00_init_rings(vha);
ha->flags.chip_reset_done = 1;
if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) {
......@@ -1233,6 +1239,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
mq_size += ha->max_rsp_queues *
(rsp->length * sizeof(response_t));
}
if (ha->tgt.atio_q_length)
mq_size += ha->tgt.atio_q_length * sizeof(request_t);
/* Allocate memory for Fibre Channel Event Buffer. */
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
goto try_eft;
......@@ -1696,6 +1704,12 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
/* Setup ATIO queue dma pointers for target mode */
icb->atio_q_inpointer = __constant_cpu_to_le16(0);
icb->atio_q_length = cpu_to_le16(ha->tgt.atio_q_length);
icb->atio_q_address[0] = cpu_to_le32(LSD(ha->tgt.atio_dma));
icb->atio_q_address[1] = cpu_to_le32(MSD(ha->tgt.atio_dma));
if (ha->mqenable || IS_QLA83XX(ha)) {
icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS);
icb->rid = __constant_cpu_to_le16(rid);
......@@ -1739,6 +1753,8 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
WRT_REG_DWORD(&reg->isp24.rsp_q_in, 0);
WRT_REG_DWORD(&reg->isp24.rsp_q_out, 0);
}
qlt_24xx_config_rings(vha, reg);
/* PCI posting */
RD_REG_DWORD(&ioreg->hccr);
}
......@@ -1794,6 +1810,11 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
spin_unlock(&ha->vport_slock);
ha->tgt.atio_ring_ptr = ha->tgt.atio_ring;
ha->tgt.atio_ring_index = 0;
/* Initialize ATIO queue entries */
qlt_init_atio_q_entries(vha);
ha->isp_ops->config_rings(vha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
......@@ -2051,6 +2072,10 @@ qla2x00_configure_hba(scsi_qla_host_t *vha)
vha->d_id.b.area = area;
vha->d_id.b.al_pa = al_pa;
spin_lock(&ha->vport_slock);
qlt_update_vp_map(vha, SET_AL_PA);
spin_unlock(&ha->vport_slock);
if (!vha->flags.init_done)
ql_log(ql_log_info, vha, 0x2010,
"Topology - %s, Host Loop address 0x%x.\n",
......@@ -2270,7 +2295,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
if (IS_QLA23XX(ha)) {
nv->firmware_options[0] |= BIT_2;
nv->firmware_options[0] &= ~BIT_3;
nv->firmware_options[0] &= ~BIT_6;
nv->special_options[0] &= ~BIT_6;
nv->add_firmware_options[1] |= BIT_5 | BIT_4;
if (IS_QLA2300(ha)) {
......@@ -2467,14 +2492,21 @@ qla2x00_rport_del(void *data)
{
fc_port_t *fcport = data;
struct fc_rport *rport;
scsi_qla_host_t *vha = fcport->vha;
unsigned long flags;
spin_lock_irqsave(fcport->vha->host->host_lock, flags);
rport = fcport->drport ? fcport->drport: fcport->rport;
fcport->drport = NULL;
spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
if (rport)
if (rport) {
fc_remote_port_delete(rport);
/*
* Release the target mode FC NEXUS in qla_target.c code
* if target mod is enabled.
*/
qlt_fc_port_deleted(vha, fcport);
}
}
/**
......@@ -2853,6 +2885,12 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
"Unable to allocate fc remote port.\n");
return;
}
/*
* Create target mode FC NEXUS in qla_target.c if target mode is
* enabled..
*/
qlt_fc_port_added(vha, fcport);
spin_lock_irqsave(fcport->vha->host->host_lock, flags);
*((fc_port_t **)rport->dd_data) = fcport;
spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
......@@ -3532,6 +3570,12 @@ qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
if (mb[10] & BIT_1)
fcport->supported_classes |= FC_COS_CLASS3;
if (IS_FWI2_CAPABLE(ha)) {
if (mb[10] & BIT_7)
fcport->flags |=
FCF_CONF_COMP_SUPPORTED;
}
rval = QLA_SUCCESS;
break;
} else if (mb[0] == MBS_LOOP_ID_USED) {
......@@ -4003,6 +4047,7 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0];
unsigned long flags;
/* If firmware needs to be loaded */
if (qla2x00_isp_firmware(vha)) {
......@@ -4027,6 +4072,16 @@ qla2x00_restart_isp(scsi_qla_host_t *vha)
qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
vha->flags.online = 1;
/*
* Process any ATIO queue entries that came in
* while we weren't online.
*/
spin_lock_irqsave(&ha->hardware_lock, flags);
if (qla_tgt_mode_enabled(vha))
qlt_24xx_process_atio_queue(vha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
/* Wait at most MAX_TARGET RSCNs for a stable link. */
wait_time = 256;
do {
......@@ -4267,6 +4322,15 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
rval = 1;
}
if (!qla_ini_mode_enabled(vha)) {
/* Don't enable full login after initial LIP */
nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_13);
/* Don't enable LIP full login for initiator */
nv->host_p &= __constant_cpu_to_le32(~BIT_10);
}
qlt_24xx_config_nvram_stage1(vha, nv);
/* Reset Initialization control block */
memset(icb, 0, ha->init_cb_size);
......@@ -4294,8 +4358,10 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
"QLA2462");
/* Use alternate WWN? */
qlt_24xx_config_nvram_stage2(vha, icb);
if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
/* Use alternate WWN? */
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
}
......
......@@ -5,6 +5,7 @@
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include "qla_def.h"
#include "qla_target.h"
#include <linux/blkdev.h>
#include <linux/delay.h>
......@@ -470,7 +471,7 @@ qla2x00_start_scsi(srb_t *sp)
/**
* qla2x00_start_iocbs() - Execute the IOCB command
*/
static void
void
qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
{
struct qla_hw_data *ha = vha->hw;
......@@ -571,6 +572,29 @@ qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
return (ret);
}
/*
* qla2x00_issue_marker
*
* Issue marker
* Caller CAN have hardware lock held as specified by ha_locked parameter.
* Might release it, then reaquire.
*/
int qla2x00_issue_marker(scsi_qla_host_t *vha, int ha_locked)
{
if (ha_locked) {
if (__qla2x00_marker(vha, vha->req, vha->req->rsp, 0, 0,
MK_SYNC_ALL) != QLA_SUCCESS)
return QLA_FUNCTION_FAILED;
} else {
if (qla2x00_marker(vha, vha->req, vha->req->rsp, 0, 0,
MK_SYNC_ALL) != QLA_SUCCESS)
return QLA_FUNCTION_FAILED;
}
vha->marker_needed = 0;
return QLA_SUCCESS;
}
/**
* qla24xx_calc_iocbs() - Determine number of Command Type 3 and
* Continuation Type 1 IOCBs to allocate.
......
......@@ -5,6 +5,7 @@
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include "qla_def.h"
#include "qla_target.h"
#include <linux/delay.h>
#include <linux/slab.h>
......@@ -473,8 +474,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
case MBA_WAKEUP_THRES: /* Request Queue Wake-up */
ql_dbg(ql_dbg_async, vha, 0x5008,
"Asynchronous WAKEUP_THRES.\n");
break;
break;
case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */
ql_dbg(ql_dbg_async, vha, 0x5009,
"LIP occurred (%x).\n", mb[1]);
......@@ -685,6 +686,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
ql_dbg(ql_dbg_async, vha, 0x5011,
"Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
mb[1], mb[2], mb[3]);
qlt_async_event(mb[0], vha, mb);
break;
}
......@@ -702,8 +705,13 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
qla2x00_mark_all_devices_lost(vha, 1);
if (vha->vp_idx == 0 && !qla_ini_mode_enabled(vha))
set_bit(SCR_PENDING, &vha->dpc_flags);
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
qlt_async_event(mb[0], vha, mb);
break;
case MBA_RSCN_UPDATE: /* State Change Registration */
......@@ -825,6 +833,8 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
mb[0], mb[1], mb[2], mb[3]);
}
qlt_async_event(mb[0], vha, mb);
if (!vha->vp_idx && ha->num_vhosts)
qla2x00_alert_all_vps(rsp, mb);
}
......@@ -1190,6 +1200,9 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
} else if (iop[0] & BIT_5)
fcport->port_type = FCT_INITIATOR;
if (iop[0] & BIT_7)
fcport->flags |= FCF_CONF_COMP_SUPPORTED;
if (logio->io_parameter[7] || logio->io_parameter[8])
fcport->supported_classes |= FC_COS_CLASS2;
if (logio->io_parameter[9] || logio->io_parameter[10])
......@@ -2004,6 +2017,9 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
if (pkt->entry_status != 0) {
qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
(void)qlt_24xx_process_response_error(vha, pkt);
((response_t *)pkt)->signature = RESPONSE_PROCESSED;
wmb();
continue;
......@@ -2034,6 +2050,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
case ELS_IOCB_TYPE:
qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
break;
case ABTS_RECV_24XX:
/* ensure that the ATIO queue is empty */
qlt_24xx_process_atio_queue(vha);
case ABTS_RESP_24XX:
case CTIO_TYPE7:
case NOTIFY_ACK_TYPE:
qlt_response_pkt_all_vps(vha, (response_t *)pkt);
break;
case MARKER_TYPE:
/* Do nothing in this case, this check is to prevent it
* from falling into default case
......@@ -2186,6 +2210,13 @@ qla24xx_intr_handler(int irq, void *dev_id)
case 0x14:
qla24xx_process_response_queue(vha, rsp);
break;
case 0x1C: /* ATIO queue updated */
qlt_24xx_process_atio_queue(vha);
break;
case 0x1D: /* ATIO and response queues updated */
qlt_24xx_process_atio_queue(vha);
qla24xx_process_response_queue(vha, rsp);
break;
default:
ql_dbg(ql_dbg_async, vha, 0x504f,
"Unrecognized interrupt type (%d).\n", stat * 0xff);
......@@ -2330,6 +2361,13 @@ qla24xx_msix_default(int irq, void *dev_id)
case 0x14:
qla24xx_process_response_queue(vha, rsp);
break;
case 0x1C: /* ATIO queue updated */
qlt_24xx_process_atio_queue(vha);
break;
case 0x1D: /* ATIO and response queues updated */
qlt_24xx_process_atio_queue(vha);
qla24xx_process_response_queue(vha, rsp);
break;
default:
ql_dbg(ql_dbg_async, vha, 0x5051,
"Unrecognized interrupt type (%d).\n", stat & 0xff);
......
......@@ -5,6 +5,7 @@
* See LICENSE.qla2xxx for copyright and licensing details.
*/
#include "qla_def.h"
#include "qla_target.h"
#include <linux/delay.h>
#include <linux/gfp.h>
......@@ -1244,6 +1245,96 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
return rval;
}
/*
* qla2x00_get_node_name_list
* Issue get node name list mailbox command, kmalloc()
* and return the resulting list. Caller must kfree() it!
*
* Input:
* ha = adapter state pointer.
* out_data = resulting list
* out_len = length of the resulting list
*
* Returns:
* qla2x00 local function return status code.
*
* Context:
* Kernel context.
*/
int
qla2x00_get_node_name_list(scsi_qla_host_t *vha, void **out_data, int *out_len)
{
struct qla_hw_data *ha = vha->hw;
struct qla_port_24xx_data *list = NULL;
void *pmap;
mbx_cmd_t mc;
dma_addr_t pmap_dma;
ulong dma_size;
int rval, left;
left = 1;
while (left > 0) {
dma_size = left * sizeof(*list);
pmap = dma_alloc_coherent(&ha->pdev->dev, dma_size,
&pmap_dma, GFP_KERNEL);
if (!pmap) {
ql_log(ql_log_warn, vha, 0x113f,
"%s(%ld): DMA Alloc failed of %ld\n",
__func__, vha->host_no, dma_size);
rval = QLA_MEMORY_ALLOC_FAILED;
goto out;
}
mc.mb[0] = MBC_PORT_NODE_NAME_LIST;
mc.mb[1] = BIT_1 | BIT_3;
mc.mb[2] = MSW(pmap_dma);
mc.mb[3] = LSW(pmap_dma);
mc.mb[6] = MSW(MSD(pmap_dma));
mc.mb[7] = LSW(MSD(pmap_dma));
mc.mb[8] = dma_size;
mc.out_mb = MBX_0|MBX_1|MBX_2|MBX_3|MBX_6|MBX_7|MBX_8;
mc.in_mb = MBX_0|MBX_1;
mc.tov = 30;
mc.flags = MBX_DMA_IN;
rval = qla2x00_mailbox_command(vha, &mc);
if (rval != QLA_SUCCESS) {
if ((mc.mb[0] == MBS_COMMAND_ERROR) &&
(mc.mb[1] == 0xA)) {
left += le16_to_cpu(mc.mb[2]) /
sizeof(struct qla_port_24xx_data);
goto restart;
}
goto out_free;
}
left = 0;
list = kzalloc(dma_size, GFP_KERNEL);
if (!list) {
ql_log(ql_log_warn, vha, 0x1140,
"%s(%ld): failed to allocate node names list "
"structure.\n", __func__, vha->host_no);
rval = QLA_MEMORY_ALLOC_FAILED;
goto out_free;
}
memcpy(list, pmap, dma_size);
restart:
dma_free_coherent(&ha->pdev->dev, dma_size, pmap, pmap_dma);
}
*out_data = list;
*out_len = dma_size;
out:
return rval;
out_free:
dma_free_coherent(&ha->pdev->dev, dma_size, pmap, pmap_dma);
return rval;
}
/*
* qla2x00_get_port_database
* Issue normal/enhanced get port database mailbox command
......@@ -1352,6 +1443,13 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt)
fcport->port_type = FCT_INITIATOR;
else
fcport->port_type = FCT_TARGET;
/* Passback COS information. */
fcport->supported_classes = (pd24->flags & PDF_CLASS_2) ?
FC_COS_CLASS2 : FC_COS_CLASS3;
if (pd24->prli_svc_param_word_3[0] & BIT_7)
fcport->flags |= FCF_CONF_COMP_SUPPORTED;
} else {
uint64_t zero = 0;
......@@ -1770,6 +1868,10 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
mb[10] |= BIT_0; /* Class 2. */
if (lg->io_parameter[9] || lg->io_parameter[10])
mb[10] |= BIT_1; /* Class 3. */
if (lg->io_parameter[0] & __constant_cpu_to_le32(BIT_7))
mb[10] |= BIT_7; /* Confirmed Completion
* Allowed
*/
}
dma_pool_free(ha->s_dma_pool, lg, lg_dma);
......@@ -3096,6 +3198,9 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
vpmod->vp_count = 1;
vpmod->vp_index1 = vha->vp_idx;
vpmod->options_idx1 = BIT_3|BIT_4|BIT_5;
qlt_modify_vp_config(vha, vpmod);
memcpy(vpmod->node_name_idx1, vha->node_name, WWN_SIZE);
memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE);
vpmod->entry_count = 1;
......@@ -3235,13 +3340,6 @@ qla2x00_send_change_request(scsi_qla_host_t *vha, uint16_t format,
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c7,
"Entered %s.\n", __func__);
/*
* This command is implicitly executed by firmware during login for the
* physical hosts
*/
if (vp_idx == 0)
return QLA_FUNCTION_FAILED;
mcp->mb[0] = MBC_SEND_CHANGE_REQUEST;
mcp->mb[1] = format;
mcp->mb[9] = vp_idx;
......
......@@ -6,6 +6,7 @@
*/
#include "qla_def.h"
#include "qla_gbl.h"
#include "qla_target.h"
#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
......@@ -49,6 +50,9 @@ qla24xx_allocate_vp_id(scsi_qla_host_t *vha)
spin_lock_irqsave(&ha->vport_slock, flags);
list_add_tail(&vha->list, &ha->vp_list);
qlt_update_vp_map(vha, SET_VP_IDX);
spin_unlock_irqrestore(&ha->vport_slock, flags);
mutex_unlock(&ha->vport_lock);
......@@ -79,6 +83,7 @@ qla24xx_deallocate_vp_id(scsi_qla_host_t *vha)
spin_lock_irqsave(&ha->vport_slock, flags);
}
list_del(&vha->list);
qlt_update_vp_map(vha, RESET_VP_IDX);
spin_unlock_irqrestore(&ha->vport_slock, flags);
vp_id = vha->vp_idx;
......@@ -150,6 +155,9 @@ qla24xx_disable_vp(scsi_qla_host_t *vha)
atomic_set(&vha->loop_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
/* Remove port id from vp target map */
qlt_update_vp_map(vha, RESET_AL_PA);
qla2x00_mark_vp_devices_dead(vha);
atomic_set(&vha->vp_state, VP_FAILED);
vha->flags.management_server_logged_in = 0;
......
......@@ -13,12 +13,13 @@
#include <linux/mutex.h>
#include <linux/kobject.h>
#include <linux/slab.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>
#include "qla_target.h"
/*
* Driver version
*/
......@@ -40,6 +41,12 @@ static struct kmem_cache *ctx_cachep;
*/
int ql_errlev = ql_log_all;
int ql2xenableclass2;
module_param(ql2xenableclass2, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xenableclass2,
"Specify if Class 2 operations are supported from the very "
"beginning. Default is 0 - class 2 not supported.");
int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO);
MODULE_PARM_DESC(ql2xlogintimeout,
......@@ -255,6 +262,8 @@ struct scsi_host_template qla2xxx_driver_template = {
.max_sectors = 0xFFFF,
.shost_attrs = qla2x00_host_attrs,
.supported_mode = MODE_INITIATOR,
};
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
......@@ -2187,6 +2196,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ql_dbg_pci(ql_dbg_init, pdev, 0x000a,
"Memory allocated for ha=%p.\n", ha);
ha->pdev = pdev;
ha->tgt.enable_class_2 = ql2xenableclass2;
/* Clear our data area */
ha->bars = bars;
......@@ -2250,6 +2260,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->mbx_count = MAILBOX_REGISTER_COUNT;
req_length = REQUEST_ENTRY_CNT_24XX;
rsp_length = RESPONSE_ENTRY_CNT_2300;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
ha->gid_list_info_size = 8;
......@@ -2265,6 +2276,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->mbx_count = MAILBOX_REGISTER_COUNT;
req_length = REQUEST_ENTRY_CNT_24XX;
rsp_length = RESPONSE_ENTRY_CNT_2300;
ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
ha->gid_list_info_size = 8;
......@@ -2433,6 +2445,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
goto probe_init_failed;
}
qlt_probe_one_stage1(base_vha, ha);
/* Set up the irqs */
ret = qla2x00_request_irqs(ha, rsp);
......@@ -2521,6 +2534,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ql_dbg(ql_dbg_init, base_vha, 0x00ee,
"DPC thread started successfully.\n");
/*
* If we're not coming up in initiator mode, we might sit for
* a while without waking up the dpc thread, which leads to a
* stuck process warning. So just kick the dpc once here and
* let the kthread start (and go back to sleep in qla2x00_do_dpc).
*/
qla2xxx_wake_dpc(base_vha);
skip_dpc:
list_add_tail(&base_vha->list, &ha->vp_list);
base_vha->host->irq = ha->pdev->irq;
......@@ -2566,7 +2587,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ql_dbg(ql_dbg_init, base_vha, 0x00f2,
"Init done and hba is online.\n");
scsi_scan_host(host);
if (qla_ini_mode_enabled(base_vha))
scsi_scan_host(host);
else
ql_dbg(ql_dbg_init, base_vha, 0x0122,
"skipping scsi_scan_host() for non-initiator port\n");
qla2x00_alloc_sysfs_attr(base_vha);
......@@ -2584,6 +2609,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
base_vha->host_no,
ha->isp_ops->fw_version_str(base_vha, fw_str));
qlt_add_target(ha, base_vha);
return 0;
probe_init_failed:
......@@ -2631,6 +2658,22 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ret;
}
static void
qla2x00_stop_dpc_thread(scsi_qla_host_t *vha)
{
struct qla_hw_data *ha = vha->hw;
struct task_struct *t = ha->dpc_thread;
if (ha->dpc_thread == NULL)
return;
/*
* qla2xxx_wake_dpc checks for ->dpc_thread
* so we need to zero it out.
*/
ha->dpc_thread = NULL;
kthread_stop(t);
}
static void
qla2x00_shutdown(struct pci_dev *pdev)
{
......@@ -2684,6 +2727,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
base_vha = pci_get_drvdata(pdev);
ha = base_vha->hw;
ha->flags.host_shutting_down = 1;
mutex_lock(&ha->vport_lock);
while (ha->cur_vport_count) {
struct Scsi_Host *scsi_host;
......@@ -2737,6 +2782,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
ha->dpc_thread = NULL;
kthread_stop(t);
}
qlt_remove_target(ha, base_vha);
qla2x00_free_sysfs_attr(base_vha);
......@@ -2788,17 +2834,7 @@ qla2x00_free_device(scsi_qla_host_t *vha)
if (vha->timer_active)
qla2x00_stop_timer(vha);
/* Kill the kernel thread for this host */
if (ha->dpc_thread) {
struct task_struct *t = ha->dpc_thread;
/*
* qla2xxx_wake_dpc checks for ->dpc_thread
* so we need to zero it out.
*/
ha->dpc_thread = NULL;
kthread_stop(t);
}
qla2x00_stop_dpc_thread(vha);
qla25xx_delete_queues(vha);
......@@ -2860,8 +2896,10 @@ qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport,
spin_unlock_irqrestore(vha->host->host_lock, flags);
set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
qla2xxx_wake_dpc(base_vha);
} else
} else {
fc_remote_port_delete(rport);
qlt_fc_port_deleted(vha, fcport);
}
}
/*
......@@ -2964,10 +3002,13 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
if (!ha->init_cb)
goto fail;
if (qlt_mem_alloc(ha) < 0)
goto fail_free_init_cb;
ha->gid_list = dma_alloc_coherent(&ha->pdev->dev,
qla2x00_gid_list_size(ha), &ha->gid_list_dma, GFP_KERNEL);
if (!ha->gid_list)
goto fail_free_init_cb;
goto fail_free_tgt_mem;
ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
if (!ha->srb_mempool)
......@@ -3185,6 +3226,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
ha->gid_list_dma);
ha->gid_list = NULL;
ha->gid_list_dma = 0;
fail_free_tgt_mem:
qlt_mem_free(ha);
fail_free_init_cb:
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb,
ha->init_cb_dma);
......@@ -3300,6 +3343,8 @@ qla2x00_mem_free(struct qla_hw_data *ha)
if (ha->ctx_mempool)
mempool_destroy(ha->ctx_mempool);
qlt_mem_free(ha);
if (ha->init_cb)
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
ha->init_cb, ha->init_cb_dma);
......@@ -3329,6 +3374,10 @@ qla2x00_mem_free(struct qla_hw_data *ha)
ha->gid_list = NULL;
ha->gid_list_dma = 0;
ha->tgt.atio_ring = NULL;
ha->tgt.atio_dma = 0;
ha->tgt.tgt_vp_map = NULL;
}
struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht,
......@@ -3757,6 +3806,16 @@ qla2x00_do_dpc(void *data)
clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
}
if (test_bit(SCR_PENDING, &base_vha->dpc_flags)) {
int ret;
ret = qla2x00_send_change_request(base_vha, 0x3, 0);
if (ret != QLA_SUCCESS)
ql_log(ql_log_warn, base_vha, 0x121,
"Failed to enable receiving of RSCN "
"requests: 0x%x.\n", ret);
clear_bit(SCR_PENDING, &base_vha->dpc_flags);
}
if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
"Quiescence mode scheduled.\n");
......@@ -4475,6 +4534,21 @@ qla2x00_module_init(void)
return -ENOMEM;
}
/* Initialize target kmem_cache and mem_pools */
ret = qlt_init();
if (ret < 0) {
kmem_cache_destroy(srb_cachep);
return ret;
} else if (ret > 0) {
/*
* If initiator mode is explictly disabled by qlt_init(),
* prevent scsi_transport_fc.c:fc_scsi_scan_rport() from
* performing scsi_scan_target() during LOOP UP event.
*/
qla2xxx_transport_functions.disable_target_scan = 1;
qla2xxx_transport_vport_functions.disable_target_scan = 1;
}
/* Derive version string. */
strcpy(qla2x00_version_str, QLA2XXX_VERSION);
if (ql2xextended_error_logging)
......@@ -4486,6 +4560,7 @@ qla2x00_module_init(void)
kmem_cache_destroy(srb_cachep);
ql_log(ql_log_fatal, NULL, 0x0002,
"fc_attach_transport failed...Failing load!.\n");
qlt_exit();
return -ENODEV;
}
......@@ -4499,6 +4574,7 @@ qla2x00_module_init(void)
fc_attach_transport(&qla2xxx_transport_vport_functions);
if (!qla2xxx_transport_vport_template) {
kmem_cache_destroy(srb_cachep);
qlt_exit();
fc_release_transport(qla2xxx_transport_template);
ql_log(ql_log_fatal, NULL, 0x0004,
"fc_attach_transport vport failed...Failing load!.\n");
......@@ -4510,6 +4586,7 @@ qla2x00_module_init(void)
ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) {
kmem_cache_destroy(srb_cachep);
qlt_exit();
fc_release_transport(qla2xxx_transport_template);
fc_release_transport(qla2xxx_transport_vport_template);
ql_log(ql_log_fatal, NULL, 0x0006,
......@@ -4529,6 +4606,7 @@ qla2x00_module_exit(void)
pci_unregister_driver(&qla2xxx_pci_driver);
qla2x00_release_firmware();
kmem_cache_destroy(srb_cachep);
qlt_exit();
if (ctx_cachep)
kmem_cache_destroy(ctx_cachep);
fc_release_transport(qla2xxx_transport_template);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright (C) 2004 - 2010 Vladislav Bolkhovitin <vst@vlnb.net>
* Copyright (C) 2004 - 2005 Leonid Stoljar
* Copyright (C) 2006 Nathaniel Clark <nate@misrule.us>
* Copyright (C) 2007 - 2010 ID7 Ltd.
*
* Forward port and refactoring to modern qla2xxx and target/configfs
*
* Copyright (C) 2010-2011 Nicholas A. Bellinger <nab@kernel.org>
*
* Additional file for the target driver support.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
/*
* This is the global def file that is useful for including from the
* target portion.
*/
#ifndef __QLA_TARGET_H
#define __QLA_TARGET_H
#include "qla_def.h"
/*
* Must be changed on any change in any initiator visible interfaces or
* data in the target add-on
*/
#define QLA2XXX_TARGET_MAGIC 269
/*
* Must be changed on any change in any target visible interfaces or
* data in the initiator
*/
#define QLA2XXX_INITIATOR_MAGIC 57222
#define QLA2XXX_INI_MODE_STR_EXCLUSIVE "exclusive"
#define QLA2XXX_INI_MODE_STR_DISABLED "disabled"
#define QLA2XXX_INI_MODE_STR_ENABLED "enabled"
#define QLA2XXX_INI_MODE_EXCLUSIVE 0
#define QLA2XXX_INI_MODE_DISABLED 1
#define QLA2XXX_INI_MODE_ENABLED 2
#define QLA2XXX_COMMAND_COUNT_INIT 250
#define QLA2XXX_IMMED_NOTIFY_COUNT_INIT 250
/*
* Used to mark which completion handles (for RIO Status's) are for CTIO's
* vs. regular (non-target) info. This is checked for in
* qla2x00_process_response_queue() to see if a handle coming back in a
* multi-complete should come to the tgt driver or be handled there by qla2xxx
*/
#define CTIO_COMPLETION_HANDLE_MARK BIT_29
#if (CTIO_COMPLETION_HANDLE_MARK <= MAX_OUTSTANDING_COMMANDS)
#error "CTIO_COMPLETION_HANDLE_MARK not larger than MAX_OUTSTANDING_COMMANDS"
#endif
#define HANDLE_IS_CTIO_COMP(h) (h & CTIO_COMPLETION_HANDLE_MARK)
/* Used to mark CTIO as intermediate */
#define CTIO_INTERMEDIATE_HANDLE_MARK BIT_30
#ifndef OF_SS_MODE_0
/*
* ISP target entries - Flags bit definitions.
*/
#define OF_SS_MODE_0 0
#define OF_SS_MODE_1 1
#define OF_SS_MODE_2 2
#define OF_SS_MODE_3 3
#define OF_EXPL_CONF BIT_5 /* Explicit Confirmation Requested */
#define OF_DATA_IN BIT_6 /* Data in to initiator */
/* (data from target to initiator) */
#define OF_DATA_OUT BIT_7 /* Data out from initiator */
/* (data from initiator to target) */
#define OF_NO_DATA (BIT_7 | BIT_6)
#define OF_INC_RC BIT_8 /* Increment command resource count */
#define OF_FAST_POST BIT_9 /* Enable mailbox fast posting. */
#define OF_CONF_REQ BIT_13 /* Confirmation Requested */
#define OF_TERM_EXCH BIT_14 /* Terminate exchange */
#define OF_SSTS BIT_15 /* Send SCSI status */
#endif
#ifndef QLA_TGT_DATASEGS_PER_CMD32
#define QLA_TGT_DATASEGS_PER_CMD32 3
#define QLA_TGT_DATASEGS_PER_CONT32 7
#define QLA_TGT_MAX_SG32(ql) \
(((ql) > 0) ? (QLA_TGT_DATASEGS_PER_CMD32 + \
QLA_TGT_DATASEGS_PER_CONT32*((ql) - 1)) : 0)
#define QLA_TGT_DATASEGS_PER_CMD64 2
#define QLA_TGT_DATASEGS_PER_CONT64 5
#define QLA_TGT_MAX_SG64(ql) \
(((ql) > 0) ? (QLA_TGT_DATASEGS_PER_CMD64 + \
QLA_TGT_DATASEGS_PER_CONT64*((ql) - 1)) : 0)
#endif
#ifndef QLA_TGT_DATASEGS_PER_CMD_24XX
#define QLA_TGT_DATASEGS_PER_CMD_24XX 1
#define QLA_TGT_DATASEGS_PER_CONT_24XX 5
#define QLA_TGT_MAX_SG_24XX(ql) \
(min(1270, ((ql) > 0) ? (QLA_TGT_DATASEGS_PER_CMD_24XX + \
QLA_TGT_DATASEGS_PER_CONT_24XX*((ql) - 1)) : 0))
#endif
#endif
#define GET_TARGET_ID(ha, iocb) ((HAS_EXTENDED_IDS(ha)) \
? le16_to_cpu((iocb)->u.isp2x.target.extended) \
: (uint16_t)(iocb)->u.isp2x.target.id.standard)
#ifndef IMMED_NOTIFY_TYPE
#define IMMED_NOTIFY_TYPE 0x0D /* Immediate notify entry. */
/*
* ISP queue - immediate notify entry structure definition.
* This is sent by the ISP to the Target driver.
* This IOCB would have report of events sent by the
* initiator, that needs to be handled by the target
* driver immediately.
*/
struct imm_ntfy_from_isp {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
union {
struct {
uint32_t sys_define_2; /* System defined. */
target_id_t target;
uint16_t lun;
uint8_t target_id;
uint8_t reserved_1;
uint16_t status_modifier;
uint16_t status;
uint16_t task_flags;
uint16_t seq_id;
uint16_t srr_rx_id;
uint32_t srr_rel_offs;
uint16_t srr_ui;
#define SRR_IU_DATA_IN 0x1
#define SRR_IU_DATA_OUT 0x5
#define SRR_IU_STATUS 0x7
uint16_t srr_ox_id;
uint8_t reserved_2[28];
} isp2x;
struct {
uint32_t reserved;
uint16_t nport_handle;
uint16_t reserved_2;
uint16_t flags;
#define NOTIFY24XX_FLAGS_GLOBAL_TPRLO BIT_1
#define NOTIFY24XX_FLAGS_PUREX_IOCB BIT_0
uint16_t srr_rx_id;
uint16_t status;
uint8_t status_subcode;
uint8_t reserved_3;
uint32_t exchange_address;
uint32_t srr_rel_offs;
uint16_t srr_ui;
uint16_t srr_ox_id;
uint8_t reserved_4[19];
uint8_t vp_index;
uint32_t reserved_5;
uint8_t port_id[3];
uint8_t reserved_6;
} isp24;
} u;
uint16_t reserved_7;
uint16_t ox_id;
} __packed;
#endif
#ifndef NOTIFY_ACK_TYPE
#define NOTIFY_ACK_TYPE 0x0E /* Notify acknowledge entry. */
/*
* ISP queue - notify acknowledge entry structure definition.
* This is sent to the ISP from the target driver.
*/
struct nack_to_isp {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
union {
struct {
uint32_t sys_define_2; /* System defined. */
target_id_t target;
uint8_t target_id;
uint8_t reserved_1;
uint16_t flags;
uint16_t resp_code;
uint16_t status;
uint16_t task_flags;
uint16_t seq_id;
uint16_t srr_rx_id;
uint32_t srr_rel_offs;
uint16_t srr_ui;
uint16_t srr_flags;
uint16_t srr_reject_code;
uint8_t srr_reject_vendor_uniq;
uint8_t srr_reject_code_expl;
uint8_t reserved_2[24];
} isp2x;
struct {
uint32_t handle;
uint16_t nport_handle;
uint16_t reserved_1;
uint16_t flags;
uint16_t srr_rx_id;
uint16_t status;
uint8_t status_subcode;
uint8_t reserved_3;
uint32_t exchange_address;
uint32_t srr_rel_offs;
uint16_t srr_ui;
uint16_t srr_flags;
uint8_t reserved_4[19];
uint8_t vp_index;
uint8_t srr_reject_vendor_uniq;
uint8_t srr_reject_code_expl;
uint8_t srr_reject_code;
uint8_t reserved_5[5];
} isp24;
} u;
uint8_t reserved[2];
uint16_t ox_id;
} __packed;
#define NOTIFY_ACK_SRR_FLAGS_ACCEPT 0
#define NOTIFY_ACK_SRR_FLAGS_REJECT 1
#define NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM 0x9
#define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL 0
#define NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_UNABLE_TO_SUPPLY_DATA 0x2a
#define NOTIFY_ACK_SUCCESS 0x01
#endif
#ifndef ACCEPT_TGT_IO_TYPE
#define ACCEPT_TGT_IO_TYPE 0x16 /* Accept target I/O entry. */
#endif
#ifndef CONTINUE_TGT_IO_TYPE
#define CONTINUE_TGT_IO_TYPE 0x17
/*
* ISP queue - Continue Target I/O (CTIO) entry for status mode 0 structure.
* This structure is sent to the ISP 2xxx from target driver.
*/
struct ctio_to_2xxx {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System defined handle */
target_id_t target;
uint16_t rx_id;
uint16_t flags;
uint16_t status;
uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */
uint16_t dseg_count; /* Data segment count. */
uint32_t relative_offset;
uint32_t residual;
uint16_t reserved_1[3];
uint16_t scsi_status;
uint32_t transfer_length;
uint32_t dseg_0_address; /* Data segment 0 address. */
uint32_t dseg_0_length; /* Data segment 0 length. */
uint32_t dseg_1_address; /* Data segment 1 address. */
uint32_t dseg_1_length; /* Data segment 1 length. */
uint32_t dseg_2_address; /* Data segment 2 address. */
uint32_t dseg_2_length; /* Data segment 2 length. */
} __packed;
#define ATIO_PATH_INVALID 0x07
#define ATIO_CANT_PROV_CAP 0x16
#define ATIO_CDB_VALID 0x3D
#define ATIO_EXEC_READ BIT_1
#define ATIO_EXEC_WRITE BIT_0
#endif
#ifndef CTIO_A64_TYPE
#define CTIO_A64_TYPE 0x1F
#define CTIO_SUCCESS 0x01
#define CTIO_ABORTED 0x02
#define CTIO_INVALID_RX_ID 0x08
#define CTIO_TIMEOUT 0x0B
#define CTIO_LIP_RESET 0x0E
#define CTIO_TARGET_RESET 0x17
#define CTIO_PORT_UNAVAILABLE 0x28
#define CTIO_PORT_LOGGED_OUT 0x29
#define CTIO_PORT_CONF_CHANGED 0x2A
#define CTIO_SRR_RECEIVED 0x45
#endif
#ifndef CTIO_RET_TYPE
#define CTIO_RET_TYPE 0x17 /* CTIO return entry */
#define ATIO_TYPE7 0x06 /* Accept target I/O entry for 24xx */
struct fcp_hdr {
uint8_t r_ctl;
uint8_t d_id[3];
uint8_t cs_ctl;
uint8_t s_id[3];
uint8_t type;
uint8_t f_ctl[3];
uint8_t seq_id;
uint8_t df_ctl;
uint16_t seq_cnt;
uint16_t ox_id;
uint16_t rx_id;
uint32_t parameter;
} __packed;
struct fcp_hdr_le {
uint8_t d_id[3];
uint8_t r_ctl;
uint8_t s_id[3];
uint8_t cs_ctl;
uint8_t f_ctl[3];
uint8_t type;
uint16_t seq_cnt;
uint8_t df_ctl;
uint8_t seq_id;
uint16_t rx_id;
uint16_t ox_id;
uint32_t parameter;
} __packed;
#define F_CTL_EXCH_CONTEXT_RESP BIT_23
#define F_CTL_SEQ_CONTEXT_RESIP BIT_22
#define F_CTL_LAST_SEQ BIT_20
#define F_CTL_END_SEQ BIT_19
#define F_CTL_SEQ_INITIATIVE BIT_16
#define R_CTL_BASIC_LINK_SERV 0x80
#define R_CTL_B_ACC 0x4
#define R_CTL_B_RJT 0x5
struct atio7_fcp_cmnd {
uint64_t lun;
uint8_t cmnd_ref;
uint8_t task_attr:3;
uint8_t reserved:5;
uint8_t task_mgmt_flags;
#define FCP_CMND_TASK_MGMT_CLEAR_ACA 6
#define FCP_CMND_TASK_MGMT_TARGET_RESET 5
#define FCP_CMND_TASK_MGMT_LU_RESET 4
#define FCP_CMND_TASK_MGMT_CLEAR_TASK_SET 2
#define FCP_CMND_TASK_MGMT_ABORT_TASK_SET 1
uint8_t wrdata:1;
uint8_t rddata:1;
uint8_t add_cdb_len:6;
uint8_t cdb[16];
/*
* add_cdb is optional and can absent from struct atio7_fcp_cmnd. Size 4
* only to make sizeof(struct atio7_fcp_cmnd) be as expected by
* BUILD_BUG_ON in qlt_init().
*/
uint8_t add_cdb[4];
/* uint32_t data_length; */
} __packed;
/*
* ISP queue - Accept Target I/O (ATIO) type entry IOCB structure.
* This is sent from the ISP to the target driver.
*/
struct atio_from_isp {
union {
struct {
uint16_t entry_hdr;
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t sys_define_2; /* System defined. */
target_id_t target;
uint16_t rx_id;
uint16_t flags;
uint16_t status;
uint8_t command_ref;
uint8_t task_codes;
uint8_t task_flags;
uint8_t execution_codes;
uint8_t cdb[MAX_CMDSZ];
uint32_t data_length;
uint16_t lun;
uint8_t initiator_port_name[WWN_SIZE]; /* on qla23xx */
uint16_t reserved_32[6];
uint16_t ox_id;
} isp2x;
struct {
uint16_t entry_hdr;
uint8_t fcp_cmnd_len_low;
uint8_t fcp_cmnd_len_high:4;
uint8_t attr:4;
uint32_t exchange_addr;
#define ATIO_EXCHANGE_ADDRESS_UNKNOWN 0xFFFFFFFF
struct fcp_hdr fcp_hdr;
struct atio7_fcp_cmnd fcp_cmnd;
} isp24;
struct {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t data[58];
uint32_t signature;
#define ATIO_PROCESSED 0xDEADDEAD /* Signature */
} raw;
} u;
} __packed;
#define CTIO_TYPE7 0x12 /* Continue target I/O entry (for 24xx) */
/*
* ISP queue - Continue Target I/O (ATIO) type 7 entry (for 24xx) structure.
* This structure is sent to the ISP 24xx from the target driver.
*/
struct ctio7_to_24xx {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System defined handle */
uint16_t nport_handle;
#define CTIO7_NHANDLE_UNRECOGNIZED 0xFFFF
uint16_t timeout;
uint16_t dseg_count; /* Data segment count. */
uint8_t vp_index;
uint8_t add_flags;
uint8_t initiator_id[3];
uint8_t reserved;
uint32_t exchange_addr;
union {
struct {
uint16_t reserved1;
uint16_t flags;
uint32_t residual;
uint16_t ox_id;
uint16_t scsi_status;
uint32_t relative_offset;
uint32_t reserved2;
uint32_t transfer_length;
uint32_t reserved3;
/* Data segment 0 address. */
uint32_t dseg_0_address[2];
/* Data segment 0 length. */
uint32_t dseg_0_length;
} status0;
struct {
uint16_t sense_length;
uint16_t flags;
uint32_t residual;
uint16_t ox_id;
uint16_t scsi_status;
uint16_t response_len;
uint16_t reserved;
uint8_t sense_data[24];
} status1;
} u;
} __packed;
/*
* ISP queue - CTIO type 7 from ISP 24xx to target driver
* returned entry structure.
*/
struct ctio7_from_24xx {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t handle; /* System defined handle */
uint16_t status;
uint16_t timeout;
uint16_t dseg_count; /* Data segment count. */
uint8_t vp_index;
uint8_t reserved1[5];
uint32_t exchange_address;
uint16_t reserved2;
uint16_t flags;
uint32_t residual;
uint16_t ox_id;
uint16_t reserved3;
uint32_t relative_offset;
uint8_t reserved4[24];
} __packed;
/* CTIO7 flags values */
#define CTIO7_FLAGS_SEND_STATUS BIT_15
#define CTIO7_FLAGS_TERMINATE BIT_14
#define CTIO7_FLAGS_CONFORM_REQ BIT_13
#define CTIO7_FLAGS_DONT_RET_CTIO BIT_8
#define CTIO7_FLAGS_STATUS_MODE_0 0
#define CTIO7_FLAGS_STATUS_MODE_1 BIT_6
#define CTIO7_FLAGS_EXPLICIT_CONFORM BIT_5
#define CTIO7_FLAGS_CONFIRM_SATISF BIT_4
#define CTIO7_FLAGS_DSD_PTR BIT_2
#define CTIO7_FLAGS_DATA_IN BIT_1
#define CTIO7_FLAGS_DATA_OUT BIT_0
#define ELS_PLOGI 0x3
#define ELS_FLOGI 0x4
#define ELS_LOGO 0x5
#define ELS_PRLI 0x20
#define ELS_PRLO 0x21
#define ELS_TPRLO 0x24
#define ELS_PDISC 0x50
#define ELS_ADISC 0x52
/*
* ISP queue - ABTS received/response entries structure definition for 24xx.
*/
#define ABTS_RECV_24XX 0x54 /* ABTS received (for 24xx) */
#define ABTS_RESP_24XX 0x55 /* ABTS responce (for 24xx) */
/*
* ISP queue - ABTS received IOCB entry structure definition for 24xx.
* The ABTS BLS received from the wire is sent to the
* target driver by the ISP 24xx.
* The IOCB is placed on the response queue.
*/
struct abts_recv_from_24xx {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint8_t reserved_1[6];
uint16_t nport_handle;
uint8_t reserved_2[2];
uint8_t vp_index;
uint8_t reserved_3:4;
uint8_t sof_type:4;
uint32_t exchange_address;
struct fcp_hdr_le fcp_hdr_le;
uint8_t reserved_4[16];
uint32_t exchange_addr_to_abort;
} __packed;
#define ABTS_PARAM_ABORT_SEQ BIT_0
struct ba_acc_le {
uint16_t reserved;
uint8_t seq_id_last;
uint8_t seq_id_valid;
#define SEQ_ID_VALID 0x80
#define SEQ_ID_INVALID 0x00
uint16_t rx_id;
uint16_t ox_id;
uint16_t high_seq_cnt;
uint16_t low_seq_cnt;
} __packed;
struct ba_rjt_le {
uint8_t vendor_uniq;
uint8_t reason_expl;
uint8_t reason_code;
#define BA_RJT_REASON_CODE_INVALID_COMMAND 0x1
#define BA_RJT_REASON_CODE_UNABLE_TO_PERFORM 0x9
uint8_t reserved;
} __packed;
/*
* ISP queue - ABTS Response IOCB entry structure definition for 24xx.
* The ABTS response to the ABTS received is sent by the
* target driver to the ISP 24xx.
* The IOCB is placed on the request queue.
*/
struct abts_resp_to_24xx {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t handle;
uint16_t reserved_1;
uint16_t nport_handle;
uint16_t control_flags;
#define ABTS_CONTR_FLG_TERM_EXCHG BIT_0
uint8_t vp_index;
uint8_t reserved_3:4;
uint8_t sof_type:4;
uint32_t exchange_address;
struct fcp_hdr_le fcp_hdr_le;
union {
struct ba_acc_le ba_acct;
struct ba_rjt_le ba_rjt;
} __packed payload;
uint32_t reserved_4;
uint32_t exchange_addr_to_abort;
} __packed;
/*
* ISP queue - ABTS Response IOCB from ISP24xx Firmware entry structure.
* The ABTS response with completion status to the ABTS response
* (sent by the target driver to the ISP 24xx) is sent by the
* ISP24xx firmware to the target driver.
* The IOCB is placed on the response queue.
*/
struct abts_resp_from_24xx_fw {
uint8_t entry_type; /* Entry type. */
uint8_t entry_count; /* Entry count. */
uint8_t sys_define; /* System defined. */
uint8_t entry_status; /* Entry Status. */
uint32_t handle;
uint16_t compl_status;
#define ABTS_RESP_COMPL_SUCCESS 0
#define ABTS_RESP_COMPL_SUBCODE_ERROR 0x31
uint16_t nport_handle;
uint16_t reserved_1;
uint8_t reserved_2;
uint8_t reserved_3:4;
uint8_t sof_type:4;
uint32_t exchange_address;
struct fcp_hdr_le fcp_hdr_le;
uint8_t reserved_4[8];
uint32_t error_subcode1;
#define ABTS_RESP_SUBCODE_ERR_ABORTED_EXCH_NOT_TERM 0x1E
uint32_t error_subcode2;
uint32_t exchange_addr_to_abort;
} __packed;
/********************************************************************\
* Type Definitions used by initiator & target halves
\********************************************************************/
struct qla_tgt_mgmt_cmd;
struct qla_tgt_sess;
/*
* This structure provides a template of function calls that the
* target driver (from within qla_target.c) can issue to the
* target module (tcm_qla2xxx).
*/
struct qla_tgt_func_tmpl {
int (*handle_cmd)(struct scsi_qla_host *, struct qla_tgt_cmd *,
unsigned char *, uint32_t, int, int, int);
int (*handle_data)(struct qla_tgt_cmd *);
int (*handle_tmr)(struct qla_tgt_mgmt_cmd *, uint32_t, uint8_t,
uint32_t);
void (*free_cmd)(struct qla_tgt_cmd *);
void (*free_mcmd)(struct qla_tgt_mgmt_cmd *);
void (*free_session)(struct qla_tgt_sess *);
int (*check_initiator_node_acl)(struct scsi_qla_host *, unsigned char *,
void *, uint8_t *, uint16_t);
struct qla_tgt_sess *(*find_sess_by_loop_id)(struct scsi_qla_host *,
const uint16_t);
struct qla_tgt_sess *(*find_sess_by_s_id)(struct scsi_qla_host *,
const uint8_t *);
void (*clear_nacl_from_fcport_map)(struct qla_tgt_sess *);
void (*put_sess)(struct qla_tgt_sess *);
void (*shutdown_sess)(struct qla_tgt_sess *);
};
int qla2x00_wait_for_hba_online(struct scsi_qla_host *);
#include <target/target_core_base.h>
#define QLA_TGT_TIMEOUT 10 /* in seconds */
#define QLA_TGT_MAX_HW_PENDING_TIME 60 /* in seconds */
/* Immediate notify status constants */
#define IMM_NTFY_LIP_RESET 0x000E
#define IMM_NTFY_LIP_LINK_REINIT 0x000F
#define IMM_NTFY_IOCB_OVERFLOW 0x0016
#define IMM_NTFY_ABORT_TASK 0x0020
#define IMM_NTFY_PORT_LOGOUT 0x0029
#define IMM_NTFY_PORT_CONFIG 0x002A
#define IMM_NTFY_GLBL_TPRLO 0x002D
#define IMM_NTFY_GLBL_LOGO 0x002E
#define IMM_NTFY_RESOURCE 0x0034
#define IMM_NTFY_MSG_RX 0x0036
#define IMM_NTFY_SRR 0x0045
#define IMM_NTFY_ELS 0x0046
/* Immediate notify task flags */
#define IMM_NTFY_TASK_MGMT_SHIFT 8
#define QLA_TGT_CLEAR_ACA 0x40
#define QLA_TGT_TARGET_RESET 0x20
#define QLA_TGT_LUN_RESET 0x10
#define QLA_TGT_CLEAR_TS 0x04
#define QLA_TGT_ABORT_TS 0x02
#define QLA_TGT_ABORT_ALL_SESS 0xFFFF
#define QLA_TGT_ABORT_ALL 0xFFFE
#define QLA_TGT_NEXUS_LOSS_SESS 0xFFFD
#define QLA_TGT_NEXUS_LOSS 0xFFFC
/* Notify Acknowledge flags */
#define NOTIFY_ACK_RES_COUNT BIT_8
#define NOTIFY_ACK_CLEAR_LIP_RESET BIT_5
#define NOTIFY_ACK_TM_RESP_CODE_VALID BIT_4
/* Command's states */
#define QLA_TGT_STATE_NEW 0 /* New command + target processing */
#define QLA_TGT_STATE_NEED_DATA 1 /* target needs data to continue */
#define QLA_TGT_STATE_DATA_IN 2 /* Data arrived + target processing */
#define QLA_TGT_STATE_PROCESSED 3 /* target done processing */
#define QLA_TGT_STATE_ABORTED 4 /* Command aborted */
/* Special handles */
#define QLA_TGT_NULL_HANDLE 0
#define QLA_TGT_SKIP_HANDLE (0xFFFFFFFF & ~CTIO_COMPLETION_HANDLE_MARK)
/* ATIO task_codes field */
#define ATIO_SIMPLE_QUEUE 0
#define ATIO_HEAD_OF_QUEUE 1
#define ATIO_ORDERED_QUEUE 2
#define ATIO_ACA_QUEUE 4
#define ATIO_UNTAGGED 5
/* TM failed response codes, see FCP (9.4.11 FCP_RSP_INFO) */
#define FC_TM_SUCCESS 0
#define FC_TM_BAD_FCP_DATA 1
#define FC_TM_BAD_CMD 2
#define FC_TM_FCP_DATA_MISMATCH 3
#define FC_TM_REJECT 4
#define FC_TM_FAILED 5
/*
* Error code of qlt_pre_xmit_response() meaning that cmd's exchange was
* terminated, so no more actions is needed and success should be returned
* to target.
*/
#define QLA_TGT_PRE_XMIT_RESP_CMD_ABORTED 0x1717
#if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G)
#define pci_dma_lo32(a) (a & 0xffffffff)
#define pci_dma_hi32(a) ((((a) >> 16)>>16) & 0xffffffff)
#else
#define pci_dma_lo32(a) (a & 0xffffffff)
#define pci_dma_hi32(a) 0
#endif
#define QLA_TGT_SENSE_VALID(sense) ((sense != NULL) && \
(((const uint8_t *)(sense))[0] & 0x70) == 0x70)
struct qla_port_24xx_data {
uint8_t port_name[WWN_SIZE];
uint16_t loop_id;
uint16_t reserved;
};
struct qla_tgt {
struct scsi_qla_host *vha;
struct qla_hw_data *ha;
/*
* To sync between IRQ handlers and qlt_target_release(). Needed,
* because req_pkt() can drop/reaquire HW lock inside. Protected by
* HW lock.
*/
int irq_cmd_count;
int datasegs_per_cmd, datasegs_per_cont, sg_tablesize;
/* Target's flags, serialized by pha->hardware_lock */
unsigned int tgt_enable_64bit_addr:1; /* 64-bits PCI addr enabled */
unsigned int link_reinit_iocb_pending:1;
/*
* Protected by tgt_mutex AND hardware_lock for writing and tgt_mutex
* OR hardware_lock for reading.
*/
int tgt_stop; /* the target mode driver is being stopped */
int tgt_stopped; /* the target mode driver has been stopped */
/* Count of sessions refering qla_tgt. Protected by hardware_lock. */
int sess_count;
/* Protected by hardware_lock. Addition also protected by tgt_mutex. */
struct list_head sess_list;
/* Protected by hardware_lock */
struct list_head del_sess_list;
struct delayed_work sess_del_work;
spinlock_t sess_work_lock;
struct list_head sess_works_list;
struct work_struct sess_work;
struct imm_ntfy_from_isp link_reinit_iocb;
wait_queue_head_t waitQ;
int notify_ack_expected;
int abts_resp_expected;
int modify_lun_expected;
int ctio_srr_id;
int imm_srr_id;
spinlock_t srr_lock;
struct list_head srr_ctio_list;
struct list_head srr_imm_list;
struct work_struct srr_work;
atomic_t tgt_global_resets_count;
struct list_head tgt_list_entry;
};
/*
* Equivilant to IT Nexus (Initiator-Target)
*/
struct qla_tgt_sess {
uint16_t loop_id;
port_id_t s_id;
unsigned int conf_compl_supported:1;
unsigned int deleted:1;
unsigned int local:1;
unsigned int tearing_down:1;
struct se_session *se_sess;
struct scsi_qla_host *vha;
struct qla_tgt *tgt;
struct list_head sess_list_entry;
unsigned long expires;
struct list_head del_list_entry;
uint8_t port_name[WWN_SIZE];
struct work_struct free_work;
};
struct qla_tgt_cmd {
struct qla_tgt_sess *sess;
int state;
struct se_cmd se_cmd;
struct work_struct free_work;
struct work_struct work;
/* Sense buffer that will be mapped into outgoing status */
unsigned char sense_buffer[TRANSPORT_SENSE_BUFFER];
/* to save extra sess dereferences */
unsigned int conf_compl_supported:1;
unsigned int sg_mapped:1;
unsigned int free_sg:1;
unsigned int aborted:1; /* Needed in case of SRR */
unsigned int write_data_transferred:1;
struct scatterlist *sg; /* cmd data buffer SG vector */
int sg_cnt; /* SG segments count */
int bufflen; /* cmd buffer length */
int offset;
uint32_t tag;
uint32_t unpacked_lun;
enum dma_data_direction dma_data_direction;
uint16_t loop_id; /* to save extra sess dereferences */
struct qla_tgt *tgt; /* to save extra sess dereferences */
struct scsi_qla_host *vha;
struct list_head cmd_list;
struct atio_from_isp atio;
};
struct qla_tgt_sess_work_param {
struct list_head sess_works_list_entry;
#define QLA_TGT_SESS_WORK_ABORT 1
#define QLA_TGT_SESS_WORK_TM 2
int type;
union {
struct abts_recv_from_24xx abts;
struct imm_ntfy_from_isp tm_iocb;
struct atio_from_isp tm_iocb2;
};
};
struct qla_tgt_mgmt_cmd {
uint8_t tmr_func;
uint8_t fc_tm_rsp;
struct qla_tgt_sess *sess;
struct se_cmd se_cmd;
struct work_struct free_work;
unsigned int flags;
#define QLA24XX_MGMT_SEND_NACK 1
union {
struct atio_from_isp atio;
struct imm_ntfy_from_isp imm_ntfy;
struct abts_recv_from_24xx abts;
} __packed orig_iocb;
};
struct qla_tgt_prm {
struct qla_tgt_cmd *cmd;
struct qla_tgt *tgt;
void *pkt;
struct scatterlist *sg; /* cmd data buffer SG vector */
int seg_cnt;
int req_cnt;
uint16_t rq_result;
uint16_t scsi_status;
unsigned char *sense_buffer;
int sense_buffer_len;
int residual;
int add_status_pkt;
};
struct qla_tgt_srr_imm {
struct list_head srr_list_entry;
int srr_id;
struct imm_ntfy_from_isp imm_ntfy;
};
struct qla_tgt_srr_ctio {
struct list_head srr_list_entry;
int srr_id;
struct qla_tgt_cmd *cmd;
};
#define QLA_TGT_XMIT_DATA 1
#define QLA_TGT_XMIT_STATUS 2
#define QLA_TGT_XMIT_ALL (QLA_TGT_XMIT_STATUS|QLA_TGT_XMIT_DATA)
#include <linux/version.h>
extern struct qla_tgt_data qla_target;
/*
* Internal function prototypes
*/
void qlt_disable_vha(struct scsi_qla_host *);
/*
* Function prototypes for qla_target.c logic used by qla2xxx LLD code.
*/
extern int qlt_add_target(struct qla_hw_data *, struct scsi_qla_host *);
extern int qlt_remove_target(struct qla_hw_data *, struct scsi_qla_host *);
extern int qlt_lport_register(struct qla_tgt_func_tmpl *, u64,
int (*callback)(struct scsi_qla_host *), void *);
extern void qlt_lport_deregister(struct scsi_qla_host *);
extern void qlt_unreg_sess(struct qla_tgt_sess *);
extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *);
extern void qlt_fc_port_deleted(struct scsi_qla_host *, fc_port_t *);
extern void qlt_set_mode(struct scsi_qla_host *ha);
extern void qlt_clear_mode(struct scsi_qla_host *ha);
extern int __init qlt_init(void);
extern void qlt_exit(void);
extern void qlt_update_vp_map(struct scsi_qla_host *, int);
/*
* This macro is used during early initializations when host->active_mode
* is not set. Right now, ha value is ignored.
*/
#define QLA_TGT_MODE_ENABLED() (ql2x_ini_mode != QLA2XXX_INI_MODE_ENABLED)
static inline bool qla_tgt_mode_enabled(struct scsi_qla_host *ha)
{
return ha->host->active_mode & MODE_TARGET;
}
static inline bool qla_ini_mode_enabled(struct scsi_qla_host *ha)
{
return ha->host->active_mode & MODE_INITIATOR;
}
static inline void qla_reverse_ini_mode(struct scsi_qla_host *ha)
{
if (ha->host->active_mode & MODE_INITIATOR)
ha->host->active_mode &= ~MODE_INITIATOR;
else
ha->host->active_mode |= MODE_INITIATOR;
}
/*
* Exported symbols from qla_target.c LLD logic used by qla2xxx code..
*/
extern void qlt_24xx_atio_pkt_all_vps(struct scsi_qla_host *,
struct atio_from_isp *);
extern void qlt_response_pkt_all_vps(struct scsi_qla_host *, response_t *);
extern int qlt_rdy_to_xfer(struct qla_tgt_cmd *);
extern int qlt_xmit_response(struct qla_tgt_cmd *, int, uint8_t);
extern void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_mcmd(struct qla_tgt_mgmt_cmd *);
extern void qlt_free_cmd(struct qla_tgt_cmd *cmd);
extern void qlt_ctio_completion(struct scsi_qla_host *, uint32_t);
extern void qlt_async_event(uint16_t, struct scsi_qla_host *, uint16_t *);
extern void qlt_enable_vha(struct scsi_qla_host *);
extern void qlt_vport_create(struct scsi_qla_host *, struct qla_hw_data *);
extern void qlt_rff_id(struct scsi_qla_host *, struct ct_sns_req *);
extern void qlt_init_atio_q_entries(struct scsi_qla_host *);
extern void qlt_24xx_process_atio_queue(struct scsi_qla_host *);
extern void qlt_24xx_config_rings(struct scsi_qla_host *,
device_reg_t __iomem *);
extern void qlt_24xx_config_nvram_stage1(struct scsi_qla_host *,
struct nvram_24xx *);
extern void qlt_24xx_config_nvram_stage2(struct scsi_qla_host *,
struct init_cb_24xx *);
extern int qlt_24xx_process_response_error(struct scsi_qla_host *,
struct sts_entry_24xx *);
extern void qlt_modify_vp_config(struct scsi_qla_host *,
struct vp_config_entry_24xx *);
extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *);
extern int qlt_mem_alloc(struct qla_hw_data *);
extern void qlt_mem_free(struct qla_hw_data *);
extern void qlt_stop_phase1(struct qla_tgt *);
extern void qlt_stop_phase2(struct qla_tgt *);
#endif /* __QLA_TARGET_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment