Patch from Grigory Eykalis <Grigory.Eykalis@dothill.com> with some changes implementing pass-through functionality

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3422 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2011-04-27 20:46:17 +00:00
parent c5b9c85591
commit 30a78b2881
6 changed files with 412 additions and 1 deletions

View File

@@ -1048,6 +1048,198 @@ static struct bin_attribute sysfs_sfp_attr = {
.read = qla2x00_sysfs_read_sfp,
};
static void
qla2x00_wait_for_passthru_completion(struct scsi_qla_host *ha)
{
unsigned long timeout;
if (unlikely(pci_channel_offline(ha->pdev)))
return;
timeout = ((ha->r_a_tov / 10 * 2) + 5) * HZ;
if (!wait_for_completion_timeout(&ha->pass_thru_intr_comp, timeout)) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"Passthru request timed out.\n"));
if (IS_QLA82XX(ha))
set_bit(FCOE_CTX_RESET_NEEDED, &ha->dpc_flags);
else {
ha->isp_ops->fw_dump(ha, 0);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
}
qla2xxx_wake_dpc(ha);
ha->pass_thru_cmd_result = 0;
ha->pass_thru_cmd_in_process = 0;
}
}
static ssize_t
qla2x00_sysfs_read_ct(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf,
loff_t off, size_t count)
{
struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
if (!ha->pass_thru_cmd_in_process || !ha->pass_thru_cmd_result) {
DEBUG3(qla_printk(KERN_WARNING, ha,
"Passthru CT response is not available.\n"));
return 0;
}
memcpy(buf, ha->pass_thru, count);
ha->pass_thru_cmd_result = 0;
ha->pass_thru_cmd_in_process = 0;
return count;
}
static ssize_t
qla2x00_sysfs_write_ct(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf,
loff_t off, size_t count)
{
struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
struct device, kobj)));
fc_ct_request_t *request = (void *)buf;
struct ct_entry_24xx *ct_iocb = NULL;
ms_iocb_entry_t *ct_iocb_2G = NULL;
unsigned long flags;
if (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
DEBUG2_3_11(qla_printk(KERN_INFO, ha,
"%s(%ld): isp reset in progress.\n",
__func__, ha->host_no));
goto ct_error0;
}
if (atomic_read(&ha->loop_state) != LOOP_READY)
goto ct_error0;
if (count < sizeof(request->ct_iu)) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"Passthru CT buffer insufficient size %zu...\n", count));
goto ct_error0;
}
if (ha->pass_thru_cmd_in_process || ha->pass_thru_cmd_result) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"Passthru CT request is already progress\n"));
goto ct_error0;
}
if (qla2x00_mgmt_svr_login(ha)) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"Passthru CT request failed to login management server\n"));
goto ct_error0;
}
ha->pass_thru_cmd_in_process = 1;
spin_lock_irqsave(&ha->hardware_lock, flags);
if (count > PAGE_SIZE) {
DEBUG2(qla_printk(KERN_INFO, ha,
"Passthru CT request excessive size %d...\n",
(int)count));
count = PAGE_SIZE;
}
memset(ha->pass_thru, 0, PAGE_SIZE);
memcpy(ha->pass_thru, &request->ct_iu, count);
if (IS_FWI2_CAPABLE(ha)) {
ct_iocb = (void *)qla2x00_req_pkt(ha);
if (ct_iocb == NULL) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"Passthru CT request failed to get request "
"packet\n"));
goto ct_error1;
}
ct_iocb->entry_type = CT_IOCB_TYPE;
ct_iocb->entry_count = 1;
ct_iocb->entry_status = 0;
ct_iocb->comp_status = __constant_cpu_to_le16(0);
if (*(buf+4) & 0xfc)
ct_iocb->nport_handle = __constant_cpu_to_le16(NPH_SNS);
else
ct_iocb->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
ct_iocb->cmd_dsd_count = __constant_cpu_to_le16(1);
ct_iocb->vp_index = ha->vp_idx;
ct_iocb->timeout = (cpu_to_le16(ha->r_a_tov / 10 * 2) + 2);
ct_iocb->rsp_dsd_count = __constant_cpu_to_le16(1);
ct_iocb->rsp_byte_count = cpu_to_le32(PAGE_SIZE);
ct_iocb->cmd_byte_count = cpu_to_le32(count);
ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma));
ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma));
ct_iocb->dseg_0_len = ct_iocb->cmd_byte_count;
ct_iocb->dseg_1_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma));
ct_iocb->dseg_1_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma));
ct_iocb->dseg_1_len = ct_iocb->rsp_byte_count;
} else {
ct_iocb_2G = (void *)qla2x00_req_pkt(ha);
if (ct_iocb_2G == NULL) {
DEBUG2(qla_printk(KERN_WARNING, ha,
"Passthru CT request failed to get request "
"packet\n"));
goto ct_error1;
}
ct_iocb_2G->entry_type = CT_IOCB_TYPE;
ct_iocb_2G->entry_count = 1;
ct_iocb_2G->entry_status = 0;
SET_TARGET_ID(ha, ct_iocb_2G->loop_id, ha->mgmt_svr_loop_id);
ct_iocb_2G->status = __constant_cpu_to_le16(0);
ct_iocb_2G->control_flags = __constant_cpu_to_le16(0);
ct_iocb_2G->timeout = (cpu_to_le16(ha->r_a_tov / 10 * 2) + 2);
ct_iocb_2G->cmd_dsd_count = __constant_cpu_to_le16(1);
ct_iocb_2G->total_dsd_count = __constant_cpu_to_le16(2);
ct_iocb_2G->rsp_bytecount = cpu_to_le32(PAGE_SIZE);
ct_iocb_2G->req_bytecount = cpu_to_le32(count);
ct_iocb_2G->dseg_req_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma));
ct_iocb_2G->dseg_req_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma));
ct_iocb_2G->dseg_req_length = ct_iocb_2G->req_bytecount;
ct_iocb_2G->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->pass_thru_dma));
ct_iocb_2G->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->pass_thru_dma));
ct_iocb_2G->dseg_rsp_length = ct_iocb_2G->rsp_bytecount;
}
wmb();
qla2x00_isp_cmd(ha);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
qla2x00_wait_for_passthru_completion(ha);
return count;
ct_error1:
ha->pass_thru_cmd_in_process = 0;
spin_unlock_irqrestore(&ha->hardware_lock, flags);
ct_error0:
DEBUG3(qla_printk(KERN_WARNING, ha,
"Passthru CT failed on scsi(%ld)\n", ha->host_no));
return 0;
}
static struct bin_attribute sysfs_ct_attr = {
.attr = {
.name = "ct",
.mode = S_IRUSR | S_IWUSR,
},
.size = 0,
.read = qla2x00_sysfs_read_ct,
.write = qla2x00_sysfs_write_ct,
};
static struct sysfs_entry {
char *name;
struct bin_attribute *attr;
@@ -1059,6 +1251,7 @@ static struct sysfs_entry {
{ "optrom_ctl", &sysfs_optrom_ctl_attr, },
{ "vpd", &sysfs_vpd_attr, 1 },
{ "sfp", &sysfs_sfp_attr, 1 },
{ "ct", &sysfs_ct_attr, },
{ NULL },
};

View File

@@ -94,6 +94,68 @@
#define LSD(x) ((uint32_t)((uint64_t)(x)))
#define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
/* CT IU */
typedef struct{
uint8_t revision;
uint8_t in_id[3];
uint8_t gs_type;
uint8_t gs_subtype;
uint8_t options;
uint8_t reserved0;
uint16_t command;
uint16_t max_rsp_size;
uint8_t fragment_id;
uint8_t reserved1[3];
} ct_iu_t;
/* CT request format */
typedef struct {
ct_iu_t ct_iu;
union {
struct {
uint8_t reserved;
uint8_t port_id[3];
} port_id;
struct {
uint8_t port_type;
uint8_t domain;
uint8_t area;
uint8_t reserved;
} gid_pt;
struct {
uint8_t reserved;
uint8_t port_id[3];
uint8_t fc4_types[32];
} rft_id;
struct {
uint8_t reserved;
uint8_t port_id[3];
uint16_t reserved2;
uint8_t fc4_feature;
uint8_t fc4_type;
} rff_id;
struct {
uint8_t reserved;
uint8_t port_id[3];
uint8_t node_name[8];
} rnn_id;
struct {
uint8_t node_name[8];
uint8_t name_len;
uint8_t sym_node_name[255];
} rsnn_nn;
struct {
uint8_t hba_indentifier[8];
} ghat;
} extended;
} fc_ct_request_t;
/*
* I/O register
*/
@@ -2251,6 +2313,7 @@ typedef struct scsi_qla_host {
#define REGISTER_FDMI_NEEDED 26
#define FCPORT_UPDATE_NEEDED 27
#define VP_DPC_NEEDED 28 /* wake up for VP dpc handling */
#define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */
uint32_t device_flags;
#define DFLG_LOCAL_DEVICES BIT_0
@@ -2275,6 +2338,7 @@ typedef struct scsi_qla_host {
#define DT_ISP5432 BIT_10
#define DT_ISP2532 BIT_11
#define DT_ISP8432 BIT_12
#define DT_ISP8021 BIT_14
#define DT_ISP_LAST (DT_ISP8432 << 1)
#define DT_IIDMA BIT_26
@@ -2298,6 +2362,7 @@ typedef struct scsi_qla_host {
#define IS_QLA5432(ha) (DT_MASK(ha) & DT_ISP5432)
#define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532)
#define IS_QLA8432(ha) (DT_MASK(ha) & DT_ISP8432)
#define IS_QLA82XX(ha) (DT_MASK(ha) & DT_ISP8021)
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
IS_QLA6312(ha) || IS_QLA6322(ha))
@@ -2473,6 +2538,9 @@ typedef struct scsi_qla_host {
struct sns_cmd_pkt *sns_cmd;
dma_addr_t sns_cmd_dma;
char *pass_thru;
dma_addr_t pass_thru_dma;
#define SFP_DEV_SIZE 256
#define SFP_BLOCK_SIZE 64
void *sfp_data;
@@ -2514,6 +2582,7 @@ typedef struct scsi_qla_host {
struct mutex vport_lock; /* Virtual port synchronization */
struct completion mbx_cmd_comp; /* Serialize mbx access */
struct completion mbx_intr_comp; /* Used for completion notification */
struct completion pass_thru_intr_comp; /* For pass thru notification */
uint32_t mbx_flags;
#define MBX_IN_PROGRESS BIT_0
@@ -2672,6 +2741,10 @@ typedef struct scsi_qla_host {
uint16_t max_npiv_vports; /* 63 or 125 per topoloty */
int cur_vport_count;
/* Pass through support */
int pass_thru_cmd_result;
int pass_thru_cmd_in_process;
struct qla_chip_state_84xx *cs84xx;
} scsi_qla_host_t;

View File

@@ -361,6 +361,7 @@ extern int qla2x00_fdmi_register(scsi_qla_host_t *);
extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *);
extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *);
extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *);
extern int qla2x00_mgmt_svr_login(scsi_qla_host_t *);
/*
* Global Function Prototypes in qla_attr.c source file.

View File

@@ -1106,7 +1106,7 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *ha)
*
* Returns 0 on success.
*/
static int
int
qla2x00_mgmt_svr_login(scsi_qla_host_t *ha)
{
int ret;

View File

@@ -16,6 +16,9 @@ static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
static void qla2x00_status_entry(scsi_qla_host_t *, void *);
static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *);
static void qla2x00_ms_entry(scsi_qla_host_t *, ms_iocb_entry_t *);
static void qla24xx_ms_entry(scsi_qla_host_t *, struct ct_entry_24xx *);
/**
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
@@ -964,6 +967,21 @@ qla2x00_process_response_queue(struct scsi_qla_host *ha)
break;
case MARKER_TYPE:
break;
case MS_IOCB_TYPE:
if (ha->outstanding_cmds[pkt->handle])
qla2x00_ms_entry(ha, (ms_iocb_entry_t *)pkt);
else {
if (ha->pass_thru_cmd_result)
DEBUG2(qla_printk(KERN_INFO, ha,
"Passthru cmd result on.\n"));
if (!ha->pass_thru_cmd_in_process)
DEBUG2(qla_printk(KERN_INFO, ha,
"Passthru in process off.\n"));
ha->pass_thru_cmd_result = 1;
complete(&ha->pass_thru_intr_comp);
}
break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
@@ -1499,6 +1517,43 @@ qla2x00_error_entry(scsi_qla_host_t *ha, sts_entry_t *pkt)
}
}
/**
* qla2x00_ms_entry() - Process a Management Server entry.
* @ha: SCSI driver HA context
* @index: Response queue out pointer
*/
static void
qla2x00_ms_entry(scsi_qla_host_t *ha, ms_iocb_entry_t *pkt)
{
srb_t *sp;
DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n",
__func__, ha->host_no, pkt, pkt->handle1));
/* Validate handle. */
if (pkt->handle1 < MAX_OUTSTANDING_COMMANDS)
sp = ha->outstanding_cmds[pkt->handle1];
else
sp = NULL;
if (sp == NULL) {
DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n",
ha->host_no));
qla_printk(KERN_WARNING, ha, "MS entry - invalid handle\n");
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
return;
}
CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->status);
CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status;
/* Free outstanding command slot. */
ha->outstanding_cmds[pkt->handle1] = NULL;
qla2x00_sp_compl(ha, sp);
}
/**
* qla24xx_mbx_completion() - Process mailbox command completions.
* @ha: SCSI driver HA context
@@ -1668,6 +1723,32 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
#endif /* CONFIG_SCSI_QLA2XXX_TARGET */
case MARKER_TYPE:
break;
case MS_IOCB_TYPE:
if (ha->outstanding_cmds[pkt->handle])
qla24xx_ms_entry(ha, (void *)pkt);
else {
if (ha->pass_thru_cmd_result)
DEBUG2(qla_printk(KERN_INFO, ha,
"Passthru cmd result on.\n"));
if (!ha->pass_thru_cmd_in_process)
DEBUG2(qla_printk(KERN_INFO, ha,
"Passthru in process off.\n"));
ha->pass_thru_cmd_result = 1;
complete(&ha->pass_thru_intr_comp);
}
break;
case ELS_IOCB_TYPE:
if (ha->pass_thru_cmd_result)
DEBUG2(qla_printk(KERN_INFO, ha,
"Passthru cmd result on.\n"));
if (!ha->pass_thru_cmd_in_process)
DEBUG2(qla_printk(KERN_INFO, ha,
"Passthru in process off.\n"));
ha->pass_thru_cmd_result = 1;
complete(&ha->pass_thru_intr_comp);
break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
@@ -1834,6 +1915,49 @@ qla24xx_intr_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
/**
* qla24xx_ms_entry() - Process a Management Server entry.
* @ha: SCSI driver HA context
* @index: Response queue out pointer
*/
static void
qla24xx_ms_entry(scsi_qla_host_t *ha, struct ct_entry_24xx *pkt)
{
srb_t *sp;
DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n",
__func__, ha->host_no, pkt, pkt->handle));
DEBUG9(printk("%s: ct pkt dump:\n", __func__));
DEBUG9(qla2x00_dump_buffer((void *)pkt, sizeof(struct ct_entry_24xx)));
/* Validate handle. */
if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
sp = ha->outstanding_cmds[pkt->handle];
else
sp = NULL;
if (sp == NULL) {
DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n",
ha->host_no));
DEBUG10(printk("scsi(%ld): MS entry - invalid handle\n",
ha->host_no));
qla_printk(KERN_WARNING, ha, "MS entry - invalid handle %d\n",
pkt->handle);
set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
return;
}
CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->comp_status);
CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status;
/* Free outstanding command slot. */
ha->outstanding_cmds[pkt->handle] = NULL;
qla2x00_sp_compl(ha, sp);
}
static irqreturn_t
qla24xx_msix_rsp_q(int irq, void *dev_id)
{

View File

@@ -1933,6 +1933,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
init_completion(&ha->mbx_cmd_comp);
complete(&ha->mbx_cmd_comp);
init_completion(&ha->mbx_intr_comp);
init_completion(&ha->pass_thru_intr_comp);
INIT_LIST_HEAD(&ha->list);
INIT_LIST_HEAD(&ha->fcports);
@@ -2347,10 +2348,23 @@ qla2x00_mem_alloc(scsi_qla_host_t *ha)
sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL);
if (!ha->ct_sns)
goto fail_free_ms_iocb;
/* Get consistent memory allocated for pass-thru commands */
ha->pass_thru = dma_alloc_coherent(&ha->pdev->dev,
PAGE_SIZE, &ha->pass_thru_dma, GFP_KERNEL);
if (!ha->pass_thru) {
qla_printk(KERN_WARNING, ha,
"Memory Allocation failed - pass_thru\n");
goto fail_free_pass_thru;
}
}
return 0;
fail_free_pass_thru:
dma_free_coherent(&ha->pdev->dev,
PAGE_SIZE, ha->pass_thru, ha->pass_thru_dma);
ha->pass_thru = NULL;
fail_free_ms_iocb:
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
ha->ms_iocb = NULL;
@@ -2468,6 +2482,10 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
(ha->request_q_length + 1) * sizeof(request_t),
ha->request_ring, ha->request_dma);
if (ha->pass_thru)
dma_free_coherent(&ha->pdev->dev,
PAGE_SIZE, ha->pass_thru, ha->pass_thru_dma);
ha->srb_mempool = NULL;
ha->eft = NULL;
ha->eft_dma = 0;
@@ -2485,6 +2503,8 @@ qla2x00_mem_free(scsi_qla_host_t *ha)
ha->gid_list = NULL;
ha->gid_list_dma = 0;
ha->pass_thru = NULL;
ha->response_ring = NULL;
ha->response_dma = 0;
ha->request_ring = NULL;