qla2xxx: Added interface to send explicit LOGO.
This patch adds interface to send explicit LOGO explicit LOGO using using ELS commands from driver. Signed-off-by: Himanshu Madhani <himanshu.madhani@qlogic.com> Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
This commit is contained in:
parent
03e8c680d9
commit
6eb54715b5
@ -823,6 +823,41 @@ static struct bin_attribute sysfs_reset_attr = {
|
|||||||
.write = qla2x00_sysfs_write_reset,
|
.write = qla2x00_sysfs_write_reset,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static ssize_t
|
||||||
|
qla2x00_issue_logo(struct file *filp, struct kobject *kobj,
|
||||||
|
struct bin_attribute *bin_attr,
|
||||||
|
char *buf, loff_t off, size_t count)
|
||||||
|
{
|
||||||
|
struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
|
||||||
|
struct device, kobj)));
|
||||||
|
int type;
|
||||||
|
int rval = 0;
|
||||||
|
port_id_t did;
|
||||||
|
|
||||||
|
type = simple_strtol(buf, NULL, 10);
|
||||||
|
|
||||||
|
did.b.domain = (type & 0x00ff0000) >> 16;
|
||||||
|
did.b.area = (type & 0x0000ff00) >> 8;
|
||||||
|
did.b.al_pa = (type & 0x000000ff);
|
||||||
|
|
||||||
|
ql_log(ql_log_info, vha, 0x70e3, "portid=%02x%02x%02x done\n",
|
||||||
|
did.b.domain, did.b.area, did.b.al_pa);
|
||||||
|
|
||||||
|
ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
|
||||||
|
|
||||||
|
rval = qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bin_attribute sysfs_issue_logo_attr = {
|
||||||
|
.attr = {
|
||||||
|
.name = "issue_logo",
|
||||||
|
.mode = S_IWUSR,
|
||||||
|
},
|
||||||
|
.size = 0,
|
||||||
|
.write = qla2x00_issue_logo,
|
||||||
|
};
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
|
qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
|
||||||
struct bin_attribute *bin_attr,
|
struct bin_attribute *bin_attr,
|
||||||
@ -937,6 +972,7 @@ static struct sysfs_entry {
|
|||||||
{ "vpd", &sysfs_vpd_attr, 1 },
|
{ "vpd", &sysfs_vpd_attr, 1 },
|
||||||
{ "sfp", &sysfs_sfp_attr, 1 },
|
{ "sfp", &sysfs_sfp_attr, 1 },
|
||||||
{ "reset", &sysfs_reset_attr, },
|
{ "reset", &sysfs_reset_attr, },
|
||||||
|
{ "issue_logo", &sysfs_issue_logo_attr, },
|
||||||
{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
|
{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
|
||||||
{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
|
{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
|
||||||
{ NULL },
|
{ NULL },
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
* | Device Discovery | 0x2016 | 0x2020-0x2022, |
|
* | Device Discovery | 0x2016 | 0x2020-0x2022, |
|
||||||
* | | | 0x2011-0x2012, |
|
* | | | 0x2011-0x2012, |
|
||||||
* | | | 0x2099-0x20a4 |
|
* | | | 0x2099-0x20a4 |
|
||||||
* | Queue Command and IO tracing | 0x3075 | 0x300b |
|
* | Queue Command and IO tracing | 0x3074 | 0x300b |
|
||||||
* | | | 0x3027-0x3028 |
|
* | | | 0x3027-0x3028 |
|
||||||
* | | | 0x303d-0x3041 |
|
* | | | 0x303d-0x3041 |
|
||||||
* | | | 0x302d,0x3033 |
|
* | | | 0x302d,0x3033 |
|
||||||
@ -27,12 +27,11 @@
|
|||||||
* | | | 0x303a |
|
* | | | 0x303a |
|
||||||
* | DPC Thread | 0x4023 | 0x4002,0x4013 |
|
* | DPC Thread | 0x4023 | 0x4002,0x4013 |
|
||||||
* | Async Events | 0x508a | 0x502b-0x502f |
|
* | Async Events | 0x508a | 0x502b-0x502f |
|
||||||
* | | | 0x5047 |
|
|
||||||
* | | | 0x5084,0x5075 |
|
* | | | 0x5084,0x5075 |
|
||||||
* | | | 0x503d,0x5044 |
|
* | | | 0x503d,0x5044 |
|
||||||
* | | | 0x507b,0x505f |
|
* | | | 0x507b,0x505f |
|
||||||
* | Timer Routines | 0x6012 | |
|
* | Timer Routines | 0x6012 | |
|
||||||
* | User Space Interactions | 0x70e2 | 0x7018,0x702e |
|
* | User Space Interactions | 0x70e65 | 0x7018,0x702e |
|
||||||
* | | | 0x7020,0x7024 |
|
* | | | 0x7020,0x7024 |
|
||||||
* | | | 0x7039,0x7045 |
|
* | | | 0x7039,0x7045 |
|
||||||
* | | | 0x7073-0x7075 |
|
* | | | 0x7073-0x7075 |
|
||||||
|
@ -310,6 +310,14 @@ struct srb_cmd {
|
|||||||
/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
|
/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */
|
||||||
#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID)
|
#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID)
|
||||||
|
|
||||||
|
struct els_logo_payload {
|
||||||
|
uint8_t opcode;
|
||||||
|
uint8_t rsvd[3];
|
||||||
|
uint8_t s_id[3];
|
||||||
|
uint8_t rsvd1[1];
|
||||||
|
uint8_t wwpn[WWN_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SRB extensions.
|
* SRB extensions.
|
||||||
*/
|
*/
|
||||||
@ -323,6 +331,15 @@ struct srb_iocb {
|
|||||||
uint16_t data[2];
|
uint16_t data[2];
|
||||||
} logio;
|
} logio;
|
||||||
struct {
|
struct {
|
||||||
|
#define ELS_DCMD_TIMEOUT 20
|
||||||
|
#define ELS_DCMD_LOGO 0x5
|
||||||
|
uint32_t flags;
|
||||||
|
uint32_t els_cmd;
|
||||||
|
struct completion comp;
|
||||||
|
struct els_logo_payload *els_logo_pyld;
|
||||||
|
dma_addr_t els_logo_pyld_dma;
|
||||||
|
} els_logo;
|
||||||
|
struct {
|
||||||
/*
|
/*
|
||||||
* Values for flags field below are as
|
* Values for flags field below are as
|
||||||
* defined in tsk_mgmt_entry struct
|
* defined in tsk_mgmt_entry struct
|
||||||
@ -383,7 +400,7 @@ struct srb_iocb {
|
|||||||
#define SRB_FXIOCB_DCMD 10
|
#define SRB_FXIOCB_DCMD 10
|
||||||
#define SRB_FXIOCB_BCMD 11
|
#define SRB_FXIOCB_BCMD 11
|
||||||
#define SRB_ABT_CMD 12
|
#define SRB_ABT_CMD 12
|
||||||
|
#define SRB_ELS_DCMD 13
|
||||||
|
|
||||||
typedef struct srb {
|
typedef struct srb {
|
||||||
atomic_t ref_count;
|
atomic_t ref_count;
|
||||||
|
@ -44,6 +44,8 @@ extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
|
|||||||
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
|
extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
|
||||||
extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
|
extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *);
|
||||||
|
|
||||||
|
extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t);
|
||||||
|
|
||||||
extern void qla2x00_update_fcports(scsi_qla_host_t *);
|
extern void qla2x00_update_fcports(scsi_qla_host_t *);
|
||||||
|
|
||||||
extern int qla2x00_abort_isp(scsi_qla_host_t *);
|
extern int qla2x00_abort_isp(scsi_qla_host_t *);
|
||||||
|
@ -258,6 +258,8 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo)
|
|||||||
if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
|
if ((IS_QLAFX00(sp->fcport->vha->hw)) &&
|
||||||
(sp->type == SRB_FXIOCB_DCMD))
|
(sp->type == SRB_FXIOCB_DCMD))
|
||||||
init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
|
init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp);
|
||||||
|
if (sp->type == SRB_ELS_DCMD)
|
||||||
|
init_completion(&sp->u.iocb_cmd.u.els_logo.comp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
|
@ -2010,6 +2010,190 @@ qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qla2x00_els_dcmd_sp_free(void *ptr, void *data)
|
||||||
|
{
|
||||||
|
struct scsi_qla_host *vha = (scsi_qla_host_t *)ptr;
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
srb_t *sp = (srb_t *)data;
|
||||||
|
struct srb_iocb *elsio = &sp->u.iocb_cmd;
|
||||||
|
|
||||||
|
kfree(sp->fcport);
|
||||||
|
|
||||||
|
if (elsio->u.els_logo.els_logo_pyld)
|
||||||
|
dma_free_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
|
||||||
|
elsio->u.els_logo.els_logo_pyld,
|
||||||
|
elsio->u.els_logo.els_logo_pyld_dma);
|
||||||
|
|
||||||
|
del_timer(&elsio->timer);
|
||||||
|
qla2x00_rel_sp(vha, sp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qla2x00_els_dcmd_iocb_timeout(void *data)
|
||||||
|
{
|
||||||
|
srb_t *sp = (srb_t *)data;
|
||||||
|
struct srb_iocb *lio = &sp->u.iocb_cmd;
|
||||||
|
fc_port_t *fcport = sp->fcport;
|
||||||
|
struct scsi_qla_host *vha = fcport->vha;
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
unsigned long flags = 0;
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_io, vha, 0x3069,
|
||||||
|
"%s Timeout, hdl=%x, portid=%02x%02x%02x\n",
|
||||||
|
sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area,
|
||||||
|
fcport->d_id.b.al_pa);
|
||||||
|
|
||||||
|
/* Abort the exchange */
|
||||||
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||||
|
if (ha->isp_ops->abort_command(sp)) {
|
||||||
|
ql_dbg(ql_dbg_io, vha, 0x3070,
|
||||||
|
"mbx abort_command failed.\n");
|
||||||
|
} else {
|
||||||
|
ql_dbg(ql_dbg_io, vha, 0x3071,
|
||||||
|
"mbx abort_command success.\n");
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||||
|
|
||||||
|
complete(&lio->u.els_logo.comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qla2x00_els_dcmd_sp_done(void *data, void *ptr, int res)
|
||||||
|
{
|
||||||
|
srb_t *sp = (srb_t *)ptr;
|
||||||
|
fc_port_t *fcport = sp->fcport;
|
||||||
|
struct srb_iocb *lio = &sp->u.iocb_cmd;
|
||||||
|
struct scsi_qla_host *vha = fcport->vha;
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_io, vha, 0x3072,
|
||||||
|
"%s hdl=%x, portid=%02x%02x%02x done\n",
|
||||||
|
sp->name, sp->handle, fcport->d_id.b.domain,
|
||||||
|
fcport->d_id.b.area, fcport->d_id.b.al_pa);
|
||||||
|
|
||||||
|
complete(&lio->u.els_logo.comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode,
|
||||||
|
port_id_t remote_did)
|
||||||
|
{
|
||||||
|
srb_t *sp;
|
||||||
|
fc_port_t *fcport = NULL;
|
||||||
|
struct srb_iocb *elsio = NULL;
|
||||||
|
struct qla_hw_data *ha = vha->hw;
|
||||||
|
struct els_logo_payload logo_pyld;
|
||||||
|
int rval = QLA_SUCCESS;
|
||||||
|
|
||||||
|
fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
|
||||||
|
if (!fcport) {
|
||||||
|
ql_log(ql_log_info, vha, 0x70e5, "fcport allocation failed\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alloc SRB structure */
|
||||||
|
sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
|
||||||
|
if (!sp) {
|
||||||
|
kfree(fcport);
|
||||||
|
ql_log(ql_log_info, vha, 0x70e6,
|
||||||
|
"SRB allocation failed\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
elsio = &sp->u.iocb_cmd;
|
||||||
|
fcport->loop_id = 0xFFFF;
|
||||||
|
fcport->d_id.b.domain = remote_did.b.domain;
|
||||||
|
fcport->d_id.b.area = remote_did.b.area;
|
||||||
|
fcport->d_id.b.al_pa = remote_did.b.al_pa;
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_io, vha, 0x3073, "portid=%02x%02x%02x done\n",
|
||||||
|
fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa);
|
||||||
|
|
||||||
|
sp->type = SRB_ELS_DCMD;
|
||||||
|
sp->name = "ELS_DCMD";
|
||||||
|
sp->fcport = fcport;
|
||||||
|
qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT);
|
||||||
|
elsio->timeout = qla2x00_els_dcmd_iocb_timeout;
|
||||||
|
sp->done = qla2x00_els_dcmd_sp_done;
|
||||||
|
sp->free = qla2x00_els_dcmd_sp_free;
|
||||||
|
|
||||||
|
elsio->u.els_logo.els_logo_pyld = dma_alloc_coherent(&ha->pdev->dev,
|
||||||
|
DMA_POOL_SIZE, &elsio->u.els_logo.els_logo_pyld_dma,
|
||||||
|
GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!elsio->u.els_logo.els_logo_pyld) {
|
||||||
|
sp->free(vha, sp);
|
||||||
|
return QLA_FUNCTION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&logo_pyld, 0, sizeof(struct els_logo_payload));
|
||||||
|
|
||||||
|
elsio->u.els_logo.els_cmd = els_opcode;
|
||||||
|
logo_pyld.opcode = els_opcode;
|
||||||
|
logo_pyld.s_id[0] = vha->d_id.b.al_pa;
|
||||||
|
logo_pyld.s_id[1] = vha->d_id.b.area;
|
||||||
|
logo_pyld.s_id[2] = vha->d_id.b.domain;
|
||||||
|
host_to_fcp_swap(logo_pyld.s_id, sizeof(uint32_t));
|
||||||
|
memcpy(&logo_pyld.wwpn, vha->port_name, WWN_SIZE);
|
||||||
|
|
||||||
|
memcpy(elsio->u.els_logo.els_logo_pyld, &logo_pyld,
|
||||||
|
sizeof(struct els_logo_payload));
|
||||||
|
|
||||||
|
rval = qla2x00_start_sp(sp);
|
||||||
|
if (rval != QLA_SUCCESS) {
|
||||||
|
sp->free(vha, sp);
|
||||||
|
return QLA_FUNCTION_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ql_dbg(ql_dbg_io, vha, 0x3074,
|
||||||
|
"%s LOGO sent, hdl=%x, loopid=%x, portid=%02x%02x%02x.\n",
|
||||||
|
sp->name, sp->handle, fcport->loop_id, fcport->d_id.b.domain,
|
||||||
|
fcport->d_id.b.area, fcport->d_id.b.al_pa);
|
||||||
|
|
||||||
|
wait_for_completion(&elsio->u.els_logo.comp);
|
||||||
|
|
||||||
|
sp->free(vha, sp);
|
||||||
|
return rval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
|
||||||
|
{
|
||||||
|
scsi_qla_host_t *vha = sp->fcport->vha;
|
||||||
|
struct srb_iocb *elsio = &sp->u.iocb_cmd;
|
||||||
|
|
||||||
|
els_iocb->entry_type = ELS_IOCB_TYPE;
|
||||||
|
els_iocb->entry_count = 1;
|
||||||
|
els_iocb->sys_define = 0;
|
||||||
|
els_iocb->entry_status = 0;
|
||||||
|
els_iocb->handle = sp->handle;
|
||||||
|
els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id);
|
||||||
|
els_iocb->tx_dsd_count = 1;
|
||||||
|
els_iocb->vp_index = vha->vp_idx;
|
||||||
|
els_iocb->sof_type = EST_SOFI3;
|
||||||
|
els_iocb->rx_dsd_count = 0;
|
||||||
|
els_iocb->opcode = elsio->u.els_logo.els_cmd;
|
||||||
|
|
||||||
|
els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
|
||||||
|
els_iocb->port_id[1] = sp->fcport->d_id.b.area;
|
||||||
|
els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
|
||||||
|
els_iocb->control_flags = 0;
|
||||||
|
|
||||||
|
els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
|
||||||
|
els_iocb->tx_address[0] =
|
||||||
|
cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
|
||||||
|
els_iocb->tx_address[1] =
|
||||||
|
cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
|
||||||
|
els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
|
||||||
|
|
||||||
|
els_iocb->rx_byte_count = 0;
|
||||||
|
els_iocb->rx_address[0] = 0;
|
||||||
|
els_iocb->rx_address[1] = 0;
|
||||||
|
els_iocb->rx_len = 0;
|
||||||
|
|
||||||
|
sp->fcport->vha->qla_stats.control_requests++;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
|
qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
|
||||||
{
|
{
|
||||||
@ -2624,6 +2808,9 @@ qla2x00_start_sp(srb_t *sp)
|
|||||||
qlafx00_abort_iocb(sp, pkt) :
|
qlafx00_abort_iocb(sp, pkt) :
|
||||||
qla24xx_abort_iocb(sp, pkt);
|
qla24xx_abort_iocb(sp, pkt);
|
||||||
break;
|
break;
|
||||||
|
case SRB_ELS_DCMD:
|
||||||
|
qla24xx_els_logo_iocb(sp, pkt);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1418,6 +1418,12 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
|
|||||||
case SRB_CT_CMD:
|
case SRB_CT_CMD:
|
||||||
type = "ct pass-through";
|
type = "ct pass-through";
|
||||||
break;
|
break;
|
||||||
|
case SRB_ELS_DCMD:
|
||||||
|
type = "Driver ELS logo";
|
||||||
|
ql_dbg(ql_dbg_user, vha, 0x5047,
|
||||||
|
"Completing %s: (%p) type=%d.\n", type, sp, sp->type);
|
||||||
|
sp->done(vha, sp, 0);
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
ql_dbg(ql_dbg_user, vha, 0x503e,
|
ql_dbg(ql_dbg_user, vha, 0x503e,
|
||||||
"Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
|
"Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
|
||||||
|
Loading…
Reference in New Issue
Block a user