[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: Nicholas A. Bellinger <nab@linux-iscsi.org>
Signed-off-by: Chad Dupuis <chad.dupuis@qlogic.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
This commit is contained in:
Nicholas Bellinger 2012-05-15 14:34:28 -04:00 коммит произвёл James Bottomley
Родитель 2c1391d395
Коммит 2d70c103fd
15 изменённых файлов: 6472 добавлений и 35 удалений

Просмотреть файл

@ -1,5 +1,5 @@
qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ 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_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 obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o

Просмотреть файл

@ -5,6 +5,7 @@
* See LICENSE.qla2xxx for copyright and licensing details. * See LICENSE.qla2xxx for copyright and licensing details.
*/ */
#include "qla_def.h" #include "qla_def.h"
#include "qla_target.h"
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/vmalloc.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(vha->host) =
fc_host_supported_speeds(base_vha->host); fc_host_supported_speeds(base_vha->host);
qlt_vport_create(vha, ha);
qla24xx_vport_disable(fc_vport, disable); qla24xx_vport_disable(fc_vport, disable);
if (ha->flags.cpu_affinity_enabled) { 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_dev_loss_tmo(vha->host) = ha->port_down_retry_count;
fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name); 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_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_max_npiv_vports(vha->host) = ha->max_npiv_vports;
fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count; fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count;

Просмотреть файл

@ -11,8 +11,8 @@
* ---------------------------------------------------------------------- * ----------------------------------------------------------------------
* | Level | Last Value Used | Holes | * | Level | Last Value Used | Holes |
* ---------------------------------------------------------------------- * ----------------------------------------------------------------------
* | Module Init and Probe | 0x0120 | 0x4b,0xba,0xfa | * | Module Init and Probe | 0x0122 | 0x4b,0xba,0xfa |
* | Mailbox commands | 0x113e | 0x111a-0x111b | * | Mailbox commands | 0x1140 | 0x111a-0x111b |
* | | | 0x112c-0x112e | * | | | 0x112c-0x112e |
* | | | 0x113a | * | | | 0x113a |
* | Device Discovery | 0x2086 | 0x2020-0x2022 | * | Device Discovery | 0x2086 | 0x2020-0x2022 |
@ -33,6 +33,9 @@
* | ISP82XX Specific | 0xb054 | 0xb024 | * | ISP82XX Specific | 0xb054 | 0xb024 |
* | MultiQ | 0xc00c | | * | MultiQ | 0xc00c | |
* | Misc | 0xd010 | | * | 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); 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 * static inline void *
qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) 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; struct qla24xx_fw_dump *fw;
uint32_t ext_mem_cnt; uint32_t ext_mem_cnt;
void *nxt; void *nxt;
void *nxt_chain;
uint32_t *last_chain = NULL;
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
if (IS_QLA82XX(ha)) if (IS_QLA82XX(ha))
@ -1092,6 +1145,16 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked)
qla24xx_copy_eft(ha, nxt); 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: qla24xx_fw_dump_failed_0:
qla2xxx_dump_post_process(base_vha, rval); 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. */ /* Chain entries -- started with MQ. */
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
nxt_chain = qla25xx_copy_mqueues(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) { if (last_chain) {
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST); *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. */ /* Chain entries -- started with MQ. */
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
nxt_chain = qla25xx_copy_mqueues(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) { if (last_chain) {
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST); *last_chain |= __constant_htonl(DUMP_CHAIN_LAST);
@ -2219,6 +2284,7 @@ copy_queue:
/* Chain entries -- started with MQ. */ /* Chain entries -- started with MQ. */
nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain);
nxt_chain = qla25xx_copy_mqueues(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) { if (last_chain) {
ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT);
*last_chain |= __constant_htonl(DUMP_CHAIN_LAST); *last_chain |= __constant_htonl(DUMP_CHAIN_LAST);

Просмотреть файл

@ -244,6 +244,7 @@ struct qla2xxx_mqueue_header {
uint32_t queue; uint32_t queue;
#define TYPE_REQUEST_QUEUE 0x1 #define TYPE_REQUEST_QUEUE 0x1
#define TYPE_RESPONSE_QUEUE 0x2 #define TYPE_RESPONSE_QUEUE 0x2
#define TYPE_ATIO_QUEUE 0x3
uint32_t number; uint32_t number;
uint32_t size; 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 * more verbosity is required. It might not
* be applicable to all the levels. * 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_2100 64 /* Number of response entries.*/
#define RESPONSE_ENTRY_CNT_2300 512 /* 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 RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/
#define ATIO_ENTRY_CNT_24XX 4096 /* Number of ATIO entries. */
struct req_que; struct req_que;
@ -1234,11 +1235,27 @@ typedef struct {
* ISP queue - response queue entry definition. * ISP queue - response queue entry definition.
*/ */
typedef struct { 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; uint32_t signature;
#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */ #define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */
} response_t; } 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 { typedef union {
uint16_t extended; uint16_t extended;
struct { struct {
@ -1749,6 +1766,7 @@ static const char * const port_state_str[] = {
#define FCF_LOGIN_NEEDED BIT_1 #define FCF_LOGIN_NEEDED BIT_1
#define FCF_FCP2_DEVICE BIT_2 #define FCF_FCP2_DEVICE BIT_2
#define FCF_ASYNC_SENT BIT_3 #define FCF_ASYNC_SENT BIT_3
#define FCF_CONF_COMP_SUPPORTED BIT_4
/* No loop ID flag. */ /* No loop ID flag. */
#define FC_NO_LOOP_ID 0x1000 #define FC_NO_LOOP_ID 0x1000
@ -2421,6 +2439,40 @@ struct qlfc_fw {
uint32_t len; 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. * 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_hdlr_active:1;
uint32_t isp82xx_reset_owner:1; uint32_t isp82xx_reset_owner:1;
uint32_t isp82xx_no_md_cap:1; uint32_t isp82xx_no_md_cap:1;
/* 28 bits */ uint32_t host_shutting_down:1;
/* 30 bits */
} flags; } flags;
/* This spinlock is used to protect "io transactions", you must /* 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; dma_addr_t md_tmplt_hdr_dma;
void *md_dump; void *md_dump;
uint32_t md_dump_size; 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 FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */
#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */ #define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */
#define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */ #define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */
#define SCR_PENDING 21 /* SCR in target mode */
uint32_t device_flags; uint32_t device_flags;
#define SWITCH_FOUND BIT_0 #define SWITCH_FOUND BIT_0
@ -2986,6 +3042,15 @@ typedef struct scsi_qla_host {
atomic_t vref_count; atomic_t vref_count;
} scsi_qla_host_t; } 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. * 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. * Global Function Prototypes in qla_iocb.c source file.
*/ */
extern uint16_t qla2x00_calc_iocbs_32(uint16_t); extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
extern uint16_t qla2x00_calc_iocbs_64(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); 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 void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t);
extern int qla24xx_dif_start_scsi(srb_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. * 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 extern int
qla2x00_init_firmware(scsi_qla_host_t *, uint16_t); qla2x00_init_firmware(scsi_qla_host_t *, uint16_t);
extern int
qla2x00_get_node_name_list(scsi_qla_host_t *, void **, int *);
extern int extern int
qla2x00_get_port_database(scsi_qla_host_t *, fc_port_t *, uint8_t); 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_sp_timeout(unsigned long);
extern void qla2x00_bsg_job_done(void *, void *, int); extern void qla2x00_bsg_job_done(void *, void *, int);
extern void qla2x00_bsg_sp_free(void *, void *); extern void qla2x00_bsg_sp_free(void *, void *);
extern void qla2x00_start_iocbs(struct scsi_qla_host *, struct req_que *);
/* Interrupt related */ /* Interrupt related */
extern irqreturn_t qla82xx_intr_handler(int, void *); extern irqreturn_t qla82xx_intr_handler(int, void *);

Просмотреть файл

@ -5,6 +5,7 @@
* See LICENSE.qla2xxx for copyright and licensing details. * See LICENSE.qla2xxx for copyright and licensing details.
*/ */
#include "qla_def.h" #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_ga_nxt(scsi_qla_host_t *, fc_port_t *);
static int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_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[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.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 */ ct_req->req.rff_id.fc4_type = 0x08; /* SCSI - FCP */
/* Execute MS IOCB */ /* Execute MS IOCB */

Просмотреть файл

@ -17,6 +17,9 @@
#include <asm/prom.h> #include <asm/prom.h>
#endif #endif
#include <target/target_core_base.h>
#include "qla_target.h"
/* /*
* QLogic ISP2x00 Hardware Support Function Prototypes. * QLogic ISP2x00 Hardware Support Function Prototypes.
*/ */
@ -518,7 +521,10 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
return QLA_FUNCTION_FAILED; return QLA_FUNCTION_FAILED;
} }
} }
if (qla_ini_mode_enabled(vha))
rval = qla2x00_init_rings(vha); rval = qla2x00_init_rings(vha);
ha->flags.chip_reset_done = 1; ha->flags.chip_reset_done = 1;
if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) { 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 * mq_size += ha->max_rsp_queues *
(rsp->length * sizeof(response_t)); (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. */ /* Allocate memory for Fibre Channel Event Buffer. */
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha)) if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
goto try_eft; 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[0] = cpu_to_le32(LSD(rsp->dma));
icb->response_q_address[1] = cpu_to_le32(MSD(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)) { if (ha->mqenable || IS_QLA83XX(ha)) {
icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS); icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS);
icb->rid = __constant_cpu_to_le16(rid); 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_in, 0);
WRT_REG_DWORD(&reg->isp24.rsp_q_out, 0); WRT_REG_DWORD(&reg->isp24.rsp_q_out, 0);
} }
qlt_24xx_config_rings(vha, reg);
/* PCI posting */ /* PCI posting */
RD_REG_DWORD(&ioreg->hccr); RD_REG_DWORD(&ioreg->hccr);
} }
@ -1794,6 +1810,11 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
spin_unlock(&ha->vport_slock); 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); ha->isp_ops->config_rings(vha);
spin_unlock_irqrestore(&ha->hardware_lock, flags); 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.area = area;
vha->d_id.b.al_pa = al_pa; 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) if (!vha->flags.init_done)
ql_log(ql_log_info, vha, 0x2010, ql_log(ql_log_info, vha, 0x2010,
"Topology - %s, Host Loop address 0x%x.\n", "Topology - %s, Host Loop address 0x%x.\n",
@ -2270,7 +2295,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha)
if (IS_QLA23XX(ha)) { if (IS_QLA23XX(ha)) {
nv->firmware_options[0] |= BIT_2; nv->firmware_options[0] |= BIT_2;
nv->firmware_options[0] &= ~BIT_3; 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; nv->add_firmware_options[1] |= BIT_5 | BIT_4;
if (IS_QLA2300(ha)) { if (IS_QLA2300(ha)) {
@ -2467,14 +2492,21 @@ qla2x00_rport_del(void *data)
{ {
fc_port_t *fcport = data; fc_port_t *fcport = data;
struct fc_rport *rport; struct fc_rport *rport;
scsi_qla_host_t *vha = fcport->vha;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(fcport->vha->host->host_lock, flags); spin_lock_irqsave(fcport->vha->host->host_lock, flags);
rport = fcport->drport ? fcport->drport: fcport->rport; rport = fcport->drport ? fcport->drport: fcport->rport;
fcport->drport = NULL; fcport->drport = NULL;
spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
if (rport) if (rport) {
fc_remote_port_delete(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"); "Unable to allocate fc remote port.\n");
return; 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); spin_lock_irqsave(fcport->vha->host->host_lock, flags);
*((fc_port_t **)rport->dd_data) = fcport; *((fc_port_t **)rport->dd_data) = fcport;
spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); 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) if (mb[10] & BIT_1)
fcport->supported_classes |= FC_COS_CLASS3; 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; rval = QLA_SUCCESS;
break; break;
} else if (mb[0] == MBS_LOOP_ID_USED) { } 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 qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0]; struct req_que *req = ha->req_q_map[0];
struct rsp_que *rsp = ha->rsp_q_map[0]; struct rsp_que *rsp = ha->rsp_q_map[0];
unsigned long flags;
/* If firmware needs to be loaded */ /* If firmware needs to be loaded */
if (qla2x00_isp_firmware(vha)) { 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); qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
vha->flags.online = 1; 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 at most MAX_TARGET RSCNs for a stable link. */
wait_time = 256; wait_time = 256;
do { do {
@ -4267,6 +4322,15 @@ qla24xx_nvram_config(scsi_qla_host_t *vha)
rval = 1; 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 */ /* Reset Initialization control block */
memset(icb, 0, ha->init_cb_size); 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), qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
"QLA2462"); "QLA2462");
/* Use alternate WWN? */ qlt_24xx_config_nvram_stage2(vha, icb);
if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { 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->node_name, nv->alternate_node_name, WWN_SIZE);
memcpy(icb->port_name, nv->alternate_port_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. * See LICENSE.qla2xxx for copyright and licensing details.
*/ */
#include "qla_def.h" #include "qla_def.h"
#include "qla_target.h"
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/delay.h> #include <linux/delay.h>
@ -470,7 +471,7 @@ queuing_error:
/** /**
* qla2x00_start_iocbs() - Execute the IOCB command * qla2x00_start_iocbs() - Execute the IOCB command
*/ */
static void void
qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req)
{ {
struct qla_hw_data *ha = vha->hw; struct qla_hw_data *ha = vha->hw;
@ -571,6 +572,29 @@ qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req,
return (ret); 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 * qla24xx_calc_iocbs() - Determine number of Command Type 3 and
* Continuation Type 1 IOCBs to allocate. * Continuation Type 1 IOCBs to allocate.

Просмотреть файл

@ -5,6 +5,7 @@
* See LICENSE.qla2xxx for copyright and licensing details. * See LICENSE.qla2xxx for copyright and licensing details.
*/ */
#include "qla_def.h" #include "qla_def.h"
#include "qla_target.h"
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -473,8 +474,8 @@ skip_rio:
case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ case MBA_WAKEUP_THRES: /* Request Queue Wake-up */
ql_dbg(ql_dbg_async, vha, 0x5008, ql_dbg(ql_dbg_async, vha, 0x5008,
"Asynchronous WAKEUP_THRES.\n"); "Asynchronous WAKEUP_THRES.\n");
break;
break;
case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */
ql_dbg(ql_dbg_async, vha, 0x5009, ql_dbg(ql_dbg_async, vha, 0x5009,
"LIP occurred (%x).\n", mb[1]); "LIP occurred (%x).\n", mb[1]);
@ -685,6 +686,8 @@ skip_rio:
ql_dbg(ql_dbg_async, vha, 0x5011, ql_dbg(ql_dbg_async, vha, 0x5011,
"Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n", "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
mb[1], mb[2], mb[3]); mb[1], mb[2], mb[3]);
qlt_async_event(mb[0], vha, mb);
break; break;
} }
@ -702,8 +705,13 @@ skip_rio:
qla2x00_mark_all_devices_lost(vha, 1); 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(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
qlt_async_event(mb[0], vha, mb);
break; break;
case MBA_RSCN_UPDATE: /* State Change Registration */ case MBA_RSCN_UPDATE: /* State Change Registration */
@ -825,6 +833,8 @@ skip_rio:
mb[0], mb[1], mb[2], mb[3]); mb[0], mb[1], mb[2], mb[3]);
} }
qlt_async_event(mb[0], vha, mb);
if (!vha->vp_idx && ha->num_vhosts) if (!vha->vp_idx && ha->num_vhosts)
qla2x00_alert_all_vps(rsp, mb); 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) } else if (iop[0] & BIT_5)
fcport->port_type = FCT_INITIATOR; 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]) if (logio->io_parameter[7] || logio->io_parameter[8])
fcport->supported_classes |= FC_COS_CLASS2; fcport->supported_classes |= FC_COS_CLASS2;
if (logio->io_parameter[9] || logio->io_parameter[10]) 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) { if (pkt->entry_status != 0) {
qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt); qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
(void)qlt_24xx_process_response_error(vha, pkt);
((response_t *)pkt)->signature = RESPONSE_PROCESSED; ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
wmb(); wmb();
continue; continue;
@ -2034,6 +2050,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
case ELS_IOCB_TYPE: case ELS_IOCB_TYPE:
qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
break; 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: case MARKER_TYPE:
/* Do nothing in this case, this check is to prevent it /* Do nothing in this case, this check is to prevent it
* from falling into default case * from falling into default case
@ -2186,6 +2210,13 @@ qla24xx_intr_handler(int irq, void *dev_id)
case 0x14: case 0x14:
qla24xx_process_response_queue(vha, rsp); qla24xx_process_response_queue(vha, rsp);
break; 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: default:
ql_dbg(ql_dbg_async, vha, 0x504f, ql_dbg(ql_dbg_async, vha, 0x504f,
"Unrecognized interrupt type (%d).\n", stat * 0xff); "Unrecognized interrupt type (%d).\n", stat * 0xff);
@ -2330,6 +2361,13 @@ qla24xx_msix_default(int irq, void *dev_id)
case 0x14: case 0x14:
qla24xx_process_response_queue(vha, rsp); qla24xx_process_response_queue(vha, rsp);
break; 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: default:
ql_dbg(ql_dbg_async, vha, 0x5051, ql_dbg(ql_dbg_async, vha, 0x5051,
"Unrecognized interrupt type (%d).\n", stat & 0xff); "Unrecognized interrupt type (%d).\n", stat & 0xff);

Просмотреть файл

@ -5,6 +5,7 @@
* See LICENSE.qla2xxx for copyright and licensing details. * See LICENSE.qla2xxx for copyright and licensing details.
*/ */
#include "qla_def.h" #include "qla_def.h"
#include "qla_target.h"
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/gfp.h> #include <linux/gfp.h>
@ -1244,6 +1245,96 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
return rval; 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 * qla2x00_get_port_database
* Issue normal/enhanced get port database mailbox command * 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; fcport->port_type = FCT_INITIATOR;
else else
fcport->port_type = FCT_TARGET; 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 { } else {
uint64_t zero = 0; 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. */ mb[10] |= BIT_0; /* Class 2. */
if (lg->io_parameter[9] || lg->io_parameter[10]) if (lg->io_parameter[9] || lg->io_parameter[10])
mb[10] |= BIT_1; /* Class 3. */ 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); 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_count = 1;
vpmod->vp_index1 = vha->vp_idx; vpmod->vp_index1 = vha->vp_idx;
vpmod->options_idx1 = BIT_3|BIT_4|BIT_5; 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->node_name_idx1, vha->node_name, WWN_SIZE);
memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE); memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE);
vpmod->entry_count = 1; 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, ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c7,
"Entered %s.\n", __func__); "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[0] = MBC_SEND_CHANGE_REQUEST;
mcp->mb[1] = format; mcp->mb[1] = format;
mcp->mb[9] = vp_idx; mcp->mb[9] = vp_idx;

Просмотреть файл

@ -6,6 +6,7 @@
*/ */
#include "qla_def.h" #include "qla_def.h"
#include "qla_gbl.h" #include "qla_gbl.h"
#include "qla_target.h"
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/vmalloc.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); spin_lock_irqsave(&ha->vport_slock, flags);
list_add_tail(&vha->list, &ha->vp_list); list_add_tail(&vha->list, &ha->vp_list);
qlt_update_vp_map(vha, SET_VP_IDX);
spin_unlock_irqrestore(&ha->vport_slock, flags); spin_unlock_irqrestore(&ha->vport_slock, flags);
mutex_unlock(&ha->vport_lock); 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); spin_lock_irqsave(&ha->vport_slock, flags);
} }
list_del(&vha->list); list_del(&vha->list);
qlt_update_vp_map(vha, RESET_VP_IDX);
spin_unlock_irqrestore(&ha->vport_slock, flags); spin_unlock_irqrestore(&ha->vport_slock, flags);
vp_id = vha->vp_idx; 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_state, LOOP_DOWN);
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); 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); qla2x00_mark_vp_devices_dead(vha);
atomic_set(&vha->vp_state, VP_FAILED); atomic_set(&vha->vp_state, VP_FAILED);
vha->flags.management_server_logged_in = 0; vha->flags.management_server_logged_in = 0;

Просмотреть файл

@ -13,12 +13,13 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <scsi/scsi_tcq.h> #include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h> #include <scsi/scsicam.h>
#include <scsi/scsi_transport.h> #include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h> #include <scsi/scsi_transport_fc.h>
#include "qla_target.h"
/* /*
* Driver version * Driver version
*/ */
@ -40,6 +41,12 @@ static struct kmem_cache *ctx_cachep;
*/ */
int ql_errlev = ql_log_all; 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; int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO); module_param(ql2xlogintimeout, int, S_IRUGO);
MODULE_PARM_DESC(ql2xlogintimeout, MODULE_PARM_DESC(ql2xlogintimeout,
@ -255,6 +262,8 @@ struct scsi_host_template qla2xxx_driver_template = {
.max_sectors = 0xFFFF, .max_sectors = 0xFFFF,
.shost_attrs = qla2x00_host_attrs, .shost_attrs = qla2x00_host_attrs,
.supported_mode = MODE_INITIATOR,
}; };
static struct scsi_transport_template *qla2xxx_transport_template = NULL; 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, ql_dbg_pci(ql_dbg_init, pdev, 0x000a,
"Memory allocated for ha=%p.\n", ha); "Memory allocated for ha=%p.\n", ha);
ha->pdev = pdev; ha->pdev = pdev;
ha->tgt.enable_class_2 = ql2xenableclass2;
/* Clear our data area */ /* Clear our data area */
ha->bars = bars; 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; ha->mbx_count = MAILBOX_REGISTER_COUNT;
req_length = REQUEST_ENTRY_CNT_24XX; req_length = REQUEST_ENTRY_CNT_24XX;
rsp_length = RESPONSE_ENTRY_CNT_2300; 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->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_24xx); ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
ha->gid_list_info_size = 8; 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; ha->mbx_count = MAILBOX_REGISTER_COUNT;
req_length = REQUEST_ENTRY_CNT_24XX; req_length = REQUEST_ENTRY_CNT_24XX;
rsp_length = RESPONSE_ENTRY_CNT_2300; 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->max_loop_id = SNS_LAST_LOOP_ID_2300;
ha->init_cb_size = sizeof(struct mid_init_cb_24xx); ha->init_cb_size = sizeof(struct mid_init_cb_24xx);
ha->gid_list_info_size = 8; ha->gid_list_info_size = 8;
@ -2433,6 +2445,7 @@ que_init:
goto probe_init_failed; goto probe_init_failed;
} }
qlt_probe_one_stage1(base_vha, ha);
/* Set up the irqs */ /* Set up the irqs */
ret = qla2x00_request_irqs(ha, rsp); ret = qla2x00_request_irqs(ha, rsp);
@ -2521,6 +2534,14 @@ que_init:
ql_dbg(ql_dbg_init, base_vha, 0x00ee, ql_dbg(ql_dbg_init, base_vha, 0x00ee,
"DPC thread started successfully.\n"); "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: skip_dpc:
list_add_tail(&base_vha->list, &ha->vp_list); list_add_tail(&base_vha->list, &ha->vp_list);
base_vha->host->irq = ha->pdev->irq; base_vha->host->irq = ha->pdev->irq;
@ -2566,7 +2587,11 @@ skip_dpc:
ql_dbg(ql_dbg_init, base_vha, 0x00f2, ql_dbg(ql_dbg_init, base_vha, 0x00f2,
"Init done and hba is online.\n"); "Init done and hba is online.\n");
if (qla_ini_mode_enabled(base_vha))
scsi_scan_host(host); 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); qla2x00_alloc_sysfs_attr(base_vha);
@ -2584,6 +2609,8 @@ skip_dpc:
base_vha->host_no, base_vha->host_no,
ha->isp_ops->fw_version_str(base_vha, fw_str)); ha->isp_ops->fw_version_str(base_vha, fw_str));
qlt_add_target(ha, base_vha);
return 0; return 0;
probe_init_failed: probe_init_failed:
@ -2631,6 +2658,22 @@ probe_out:
return ret; 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 static void
qla2x00_shutdown(struct pci_dev *pdev) qla2x00_shutdown(struct pci_dev *pdev)
{ {
@ -2684,6 +2727,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
base_vha = pci_get_drvdata(pdev); base_vha = pci_get_drvdata(pdev);
ha = base_vha->hw; ha = base_vha->hw;
ha->flags.host_shutting_down = 1;
mutex_lock(&ha->vport_lock); mutex_lock(&ha->vport_lock);
while (ha->cur_vport_count) { while (ha->cur_vport_count) {
struct Scsi_Host *scsi_host; struct Scsi_Host *scsi_host;
@ -2737,6 +2782,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
ha->dpc_thread = NULL; ha->dpc_thread = NULL;
kthread_stop(t); kthread_stop(t);
} }
qlt_remove_target(ha, base_vha);
qla2x00_free_sysfs_attr(base_vha); qla2x00_free_sysfs_attr(base_vha);
@ -2788,17 +2834,7 @@ qla2x00_free_device(scsi_qla_host_t *vha)
if (vha->timer_active) if (vha->timer_active)
qla2x00_stop_timer(vha); qla2x00_stop_timer(vha);
/* Kill the kernel thread for this host */ qla2x00_stop_dpc_thread(vha);
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);
}
qla25xx_delete_queues(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); spin_unlock_irqrestore(vha->host->host_lock, flags);
set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags);
qla2xxx_wake_dpc(base_vha); qla2xxx_wake_dpc(base_vha);
} else } else {
fc_remote_port_delete(rport); 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) if (!ha->init_cb)
goto fail; goto fail;
if (qlt_mem_alloc(ha) < 0)
goto fail_free_init_cb;
ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, ha->gid_list = dma_alloc_coherent(&ha->pdev->dev,
qla2x00_gid_list_size(ha), &ha->gid_list_dma, GFP_KERNEL); qla2x00_gid_list_size(ha), &ha->gid_list_dma, GFP_KERNEL);
if (!ha->gid_list) 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); ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep);
if (!ha->srb_mempool) if (!ha->srb_mempool)
@ -3185,6 +3226,8 @@ fail_free_gid_list:
ha->gid_list_dma); ha->gid_list_dma);
ha->gid_list = NULL; ha->gid_list = NULL;
ha->gid_list_dma = 0; ha->gid_list_dma = 0;
fail_free_tgt_mem:
qlt_mem_free(ha);
fail_free_init_cb: fail_free_init_cb:
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb,
ha->init_cb_dma); ha->init_cb_dma);
@ -3300,6 +3343,8 @@ qla2x00_mem_free(struct qla_hw_data *ha)
if (ha->ctx_mempool) if (ha->ctx_mempool)
mempool_destroy(ha->ctx_mempool); mempool_destroy(ha->ctx_mempool);
qlt_mem_free(ha);
if (ha->init_cb) if (ha->init_cb)
dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
ha->init_cb, ha->init_cb_dma); 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 = NULL;
ha->gid_list_dma = 0; 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, 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); 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)) { if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) {
ql_dbg(ql_dbg_dpc, base_vha, 0x4009, ql_dbg(ql_dbg_dpc, base_vha, 0x4009,
"Quiescence mode scheduled.\n"); "Quiescence mode scheduled.\n");
@ -4475,6 +4534,21 @@ qla2x00_module_init(void)
return -ENOMEM; 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. */ /* Derive version string. */
strcpy(qla2x00_version_str, QLA2XXX_VERSION); strcpy(qla2x00_version_str, QLA2XXX_VERSION);
if (ql2xextended_error_logging) if (ql2xextended_error_logging)
@ -4486,6 +4560,7 @@ qla2x00_module_init(void)
kmem_cache_destroy(srb_cachep); kmem_cache_destroy(srb_cachep);
ql_log(ql_log_fatal, NULL, 0x0002, ql_log(ql_log_fatal, NULL, 0x0002,
"fc_attach_transport failed...Failing load!.\n"); "fc_attach_transport failed...Failing load!.\n");
qlt_exit();
return -ENODEV; return -ENODEV;
} }
@ -4499,6 +4574,7 @@ qla2x00_module_init(void)
fc_attach_transport(&qla2xxx_transport_vport_functions); fc_attach_transport(&qla2xxx_transport_vport_functions);
if (!qla2xxx_transport_vport_template) { if (!qla2xxx_transport_vport_template) {
kmem_cache_destroy(srb_cachep); kmem_cache_destroy(srb_cachep);
qlt_exit();
fc_release_transport(qla2xxx_transport_template); fc_release_transport(qla2xxx_transport_template);
ql_log(ql_log_fatal, NULL, 0x0004, ql_log(ql_log_fatal, NULL, 0x0004,
"fc_attach_transport vport failed...Failing load!.\n"); "fc_attach_transport vport failed...Failing load!.\n");
@ -4510,6 +4586,7 @@ qla2x00_module_init(void)
ret = pci_register_driver(&qla2xxx_pci_driver); ret = pci_register_driver(&qla2xxx_pci_driver);
if (ret) { if (ret) {
kmem_cache_destroy(srb_cachep); kmem_cache_destroy(srb_cachep);
qlt_exit();
fc_release_transport(qla2xxx_transport_template); fc_release_transport(qla2xxx_transport_template);
fc_release_transport(qla2xxx_transport_vport_template); fc_release_transport(qla2xxx_transport_vport_template);
ql_log(ql_log_fatal, NULL, 0x0006, ql_log(ql_log_fatal, NULL, 0x0006,
@ -4529,6 +4606,7 @@ qla2x00_module_exit(void)
pci_unregister_driver(&qla2xxx_pci_driver); pci_unregister_driver(&qla2xxx_pci_driver);
qla2x00_release_firmware(); qla2x00_release_firmware();
kmem_cache_destroy(srb_cachep); kmem_cache_destroy(srb_cachep);
qlt_exit();
if (ctx_cachep) if (ctx_cachep)
kmem_cache_destroy(ctx_cachep); kmem_cache_destroy(ctx_cachep);
fc_release_transport(qla2xxx_transport_template); fc_release_transport(qla2xxx_transport_template);

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу