Commit ac280b67 authored by Andrew Vasquez's avatar Andrew Vasquez Committed by James Bottomley

[SCSI] qla2xxx: Add asynchronous-login support.

ISPs which support this feature include 23xx and above.
Signed-off-by: default avatarAndrew Vasquez <andrew.vasquez@qlogic.com>
Signed-off-by: default avatarGiridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent cf53b069
......@@ -206,6 +206,28 @@ typedef struct srb {
*/
#define SRB_DMA_VALID BIT_0 /* Command sent to ISP */
/*
* SRB extensions.
*/
struct srb_ctx {
#define SRB_LOGIN_CMD 1
#define SRB_LOGOUT_CMD 2
uint16_t type;
struct timer_list timer;
void (*free)(srb_t *sp);
void (*timeout)(srb_t *sp);
};
struct srb_logio {
struct srb_ctx ctx;
#define SRB_LOGIN_RETRIED BIT_0
#define SRB_LOGIN_COND_PLOGI BIT_1
#define SRB_LOGIN_SKIP_PRLI BIT_2
uint16_t flags;
};
/*
* ISP I/O Register Set structure definitions.
*/
......@@ -2096,6 +2118,10 @@ struct qla_msix_entry {
enum qla_work_type {
QLA_EVT_AEN,
QLA_EVT_IDC_ACK,
QLA_EVT_ASYNC_LOGIN,
QLA_EVT_ASYNC_LOGIN_DONE,
QLA_EVT_ASYNC_LOGOUT,
QLA_EVT_ASYNC_LOGOUT_DONE,
};
......@@ -2114,6 +2140,11 @@ struct qla_work_evt {
#define QLA_IDC_ACK_REGS 7
uint16_t mb[QLA_IDC_ACK_REGS];
} idc_ack;
struct {
struct fc_port *fcport;
#define QLA_LOGIO_LOGIN_RETRIED BIT_0
u16 data[2];
} logio;
} u;
};
......@@ -2354,6 +2385,7 @@ struct qla_hw_data {
(ha)->flags.msix_enabled)
#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha))
#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha))
#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha))
#define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA)
#define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2)
......
......@@ -52,6 +52,14 @@ extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
extern void qla84xx_put_chip(struct scsi_qla_host *);
extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *);
extern int qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
/*
* Global Data in qla_os.c source file.
*/
......@@ -76,6 +84,15 @@ extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
fc_host_event_code, u32);
extern int qla2x00_post_idc_ack_work(struct scsi_qla_host *, uint16_t *);
extern int qla2x00_post_async_login_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_login_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *,
uint16_t *);
extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *,
fc_port_t *, uint16_t *);
extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *);
extern void qla2x00_abort_fcport_cmds(fc_port_t *);
......@@ -83,6 +100,8 @@ extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *,
struct qla_hw_data *);
extern void qla2x00_free_host(struct scsi_qla_host *);
extern void qla2x00_relogin(struct scsi_qla_host *);
extern void qla2x00_do_work(struct scsi_qla_host *);
/*
* Global Functions in qla_mid.c source file.
*/
......@@ -135,6 +154,7 @@ int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
uint16_t, uint16_t, uint8_t);
int __qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *,
uint16_t, uint16_t, uint8_t);
extern int qla2x00_start_sp(srb_t *);
/*
* Global Function Prototypes in qla_mbx.c source file.
......
......@@ -40,6 +40,210 @@ static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
static int qla84xx_init_chip(scsi_qla_host_t *);
static int qla25xx_init_queues(struct qla_hw_data *);
/* SRB Extensions ---------------------------------------------------------- */
static void
qla2x00_ctx_sp_timeout(unsigned long __data)
{
srb_t *sp = (srb_t *)__data;
struct srb_ctx *ctx;
fc_port_t *fcport = sp->fcport;
struct qla_hw_data *ha = fcport->vha->hw;
struct req_que *req;
unsigned long flags;
spin_lock_irqsave(&ha->hardware_lock, flags);
req = ha->req_q_map[0];
req->outstanding_cmds[sp->handle] = NULL;
ctx = sp->ctx;
ctx->timeout(sp);
spin_unlock_irqrestore(&ha->hardware_lock, flags);
ctx->free(sp);
}
static void
qla2x00_ctx_sp_free(srb_t *sp)
{
struct srb_ctx *ctx = sp->ctx;
kfree(ctx);
mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
}
inline srb_t *
qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,
unsigned long tmo)
{
srb_t *sp;
struct qla_hw_data *ha = vha->hw;
struct srb_ctx *ctx;
sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
if (!sp)
goto done;
ctx = kzalloc(size, GFP_KERNEL);
if (!ctx) {
mempool_free(sp, ha->srb_mempool);
goto done;
}
memset(sp, 0, sizeof(*sp));
sp->fcport = fcport;
sp->ctx = ctx;
ctx->free = qla2x00_ctx_sp_free;
init_timer(&ctx->timer);
if (!tmo)
goto done;
ctx->timer.expires = jiffies + tmo * HZ;
ctx->timer.data = (unsigned long)sp;
ctx->timer.function = qla2x00_ctx_sp_timeout;
add_timer(&ctx->timer);
done:
return sp;
}
/* Asynchronous Login/Logout Routines -------------------------------------- */
#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
static void
qla2x00_async_logio_timeout(srb_t *sp)
{
fc_port_t *fcport = sp->fcport;
struct srb_logio *lio = sp->ctx;
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s timeout.\n",
fcport->vha->host_no, sp->handle,
lio->ctx.type == SRB_LOGIN_CMD ? "login": "logout"));
if (lio->ctx.type == SRB_LOGIN_CMD)
qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
}
int
qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_logio *lio;
int rval;
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
ELS_TMO_2_RATOV(ha) + 2);
if (!sp)
goto done;
lio = sp->ctx;
lio->ctx.type = SRB_LOGIN_CMD;
lio->ctx.timeout = qla2x00_async_logio_timeout;
lio->flags |= SRB_LOGIN_COND_PLOGI;
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
lio->flags |= SRB_LOGIN_RETRIED;
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
DEBUG2(printk(KERN_DEBUG
"scsi(%ld:%x): Async-login - loop-id=%x portid=%02x%02x%02x "
"retries=%d.\n", fcport->vha->host_no, sp->handle, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
fcport->login_retry));
return rval;
done_free_sp:
del_timer_sync(&lio->ctx.timer);
lio->ctx.free(sp);
done:
return rval;
}
int
qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
{
struct qla_hw_data *ha = vha->hw;
srb_t *sp;
struct srb_logio *lio;
int rval;
rval = QLA_FUNCTION_FAILED;
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_logio),
ELS_TMO_2_RATOV(ha) + 2);
if (!sp)
goto done;
lio = sp->ctx;
lio->ctx.type = SRB_LOGOUT_CMD;
lio->ctx.timeout = qla2x00_async_logio_timeout;
rval = qla2x00_start_sp(sp);
if (rval != QLA_SUCCESS)
goto done_free_sp;
DEBUG2(printk(KERN_DEBUG
"scsi(%ld:%x): Async-logout - loop-id=%x portid=%02x%02x%02x.\n",
fcport->vha->host_no, sp->handle, fcport->loop_id,
fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
return rval;
done_free_sp:
del_timer_sync(&lio->ctx.timer);
lio->ctx.free(sp);
done:
return rval;
}
int
qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
int rval;
uint8_t opts = 0;
switch (data[0]) {
case MBS_COMMAND_COMPLETE:
if (fcport->flags & FCF_TAPE_PRESENT)
opts |= BIT_1;
rval = qla2x00_get_port_database(vha, fcport, opts);
if (rval != QLA_SUCCESS)
qla2x00_mark_device_lost(vha, fcport, 1, 0);
else
qla2x00_update_fcport(vha, fcport);
break;
case MBS_COMMAND_ERROR:
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
else
qla2x00_mark_device_lost(vha, fcport, 1, 0);
break;
case MBS_PORT_ID_USED:
fcport->loop_id = data[1];
qla2x00_post_async_login_work(vha, fcport, NULL);
break;
case MBS_LOOP_ID_USED:
fcport->loop_id++;
rval = qla2x00_find_new_loop_id(vha, fcport);
if (rval != QLA_SUCCESS) {
qla2x00_mark_device_lost(vha, fcport, 1, 0);
break;
}
qla2x00_post_async_login_work(vha, fcport, NULL);
break;
}
return QLA_SUCCESS;
}
int
qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
uint16_t *data)
{
qla2x00_mark_device_lost(vha, fcport, 1, 0);
return QLA_SUCCESS;
}
/****************************************************************************/
/* QLogic ISP2x00 Hardware Support Functions. */
/****************************************************************************/
......@@ -1977,7 +2181,7 @@ qla2x00_rport_del(void *data)
struct fc_rport *rport;
spin_lock_irq(fcport->vha->host->host_lock);
rport = fcport->drport;
rport = fcport->drport ? fcport->drport: fcport->rport;
fcport->drport = NULL;
spin_unlock_irq(fcport->vha->host->host_lock);
if (rport)
......@@ -2344,8 +2548,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
struct fc_rport *rport;
struct qla_hw_data *ha = vha->hw;
if (fcport->drport)
qla2x00_rport_del(fcport);
qla2x00_rport_del(fcport);
rport_ids.node_name = wwn_to_u64(fcport->node_name);
rport_ids.port_name = wwn_to_u64(fcport->port_name);
......@@ -3038,6 +3241,12 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,
rval = QLA_SUCCESS;
retry = 0;
if (IS_ALOGIO_CAPABLE(ha)) {
rval = qla2x00_post_async_login_work(vha, fcport, NULL);
if (!rval)
return rval;
}
rval = qla2x00_fabric_login(vha, fcport, next_loopid);
if (rval == QLA_SUCCESS) {
/* Send an ADISC to tape devices.*/
......
......@@ -860,3 +860,205 @@ static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp)
else
*rsp = ha->rsp_q_map[0];
}
/* Generic Control-SRB manipulation functions. */
static void *
qla2x00_alloc_iocbs(srb_t *sp)
{
scsi_qla_host_t *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
struct req_que *req = ha->req_q_map[0];
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
uint32_t index, handle;
request_t *pkt;
uint16_t cnt, req_cnt;
pkt = NULL;
req_cnt = 1;
/* Check for room in outstanding command list. */
handle = req->current_outstanding_cmd;
for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
handle++;
if (handle == MAX_OUTSTANDING_COMMANDS)
handle = 1;
if (!req->outstanding_cmds[handle])
break;
}
if (index == MAX_OUTSTANDING_COMMANDS)
goto queuing_error;
/* Check for room on request queue. */
if (req->cnt < req_cnt) {
if (ha->mqenable)
cnt = RD_REG_DWORD(&reg->isp25mq.req_q_out);
else if (IS_FWI2_CAPABLE(ha))
cnt = RD_REG_DWORD(&reg->isp24.req_q_out);
else
cnt = qla2x00_debounce_register(
ISP_REQ_Q_OUT(ha, &reg->isp));
if (req->ring_index < cnt)
req->cnt = cnt - req->ring_index;
else
req->cnt = req->length -
(req->ring_index - cnt);
}
if (req->cnt < req_cnt)
goto queuing_error;
/* Prep packet */
req->current_outstanding_cmd = handle;
req->outstanding_cmds[handle] = sp;
req->cnt -= req_cnt;
pkt = req->ring_ptr;
memset(pkt, 0, REQUEST_ENTRY_SIZE);
pkt->entry_count = req_cnt;
pkt->handle = handle;
sp->handle = handle;
queuing_error:
return pkt;
}
static void
qla2x00_start_iocbs(srb_t *sp)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
struct req_que *req = ha->req_q_map[0];
device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id);
struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
/* Adjust ring index. */
req->ring_index++;
if (req->ring_index == req->length) {
req->ring_index = 0;
req->ring_ptr = req->ring;
} else
req->ring_ptr++;
/* Set chip new ring index. */
if (ha->mqenable) {
WRT_REG_DWORD(&reg->isp25mq.req_q_in, req->ring_index);
RD_REG_DWORD(&ioreg->hccr);
} else if (IS_FWI2_CAPABLE(ha)) {
WRT_REG_DWORD(&reg->isp24.req_q_in, req->ring_index);
RD_REG_DWORD_RELAXED(&reg->isp24.req_q_in);
} else {
WRT_REG_WORD(ISP_REQ_Q_IN(ha, &reg->isp), req->ring_index);
RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, &reg->isp));
}
}
static void
qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio)
{
struct srb_logio *lio = sp->ctx;
logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI);
if (lio->flags & SRB_LOGIN_COND_PLOGI)
logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI);
if (lio->flags & SRB_LOGIN_SKIP_PRLI)
logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI);
logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
logio->port_id[0] = sp->fcport->d_id.b.al_pa;
logio->port_id[1] = sp->fcport->d_id.b.area;
logio->port_id[2] = sp->fcport->d_id.b.domain;
logio->vp_index = sp->fcport->vp_idx;
}
static void
qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
struct srb_logio *lio = sp->ctx;
uint16_t opts;
mbx->entry_type = MBX_IOCB_TYPE;;
SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
opts = lio->flags & SRB_LOGIN_COND_PLOGI ? BIT_0: 0;
opts |= lio->flags & SRB_LOGIN_SKIP_PRLI ? BIT_1: 0;
if (HAS_EXTENDED_IDS(ha)) {
mbx->mb1 = cpu_to_le16(sp->fcport->loop_id);
mbx->mb10 = cpu_to_le16(opts);
} else {
mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | opts);
}
mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain);
mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 |
sp->fcport->d_id.b.al_pa);
mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx);
}
static void
qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio)
{
logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
logio->control_flags =
cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO);
logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
logio->port_id[0] = sp->fcport->d_id.b.al_pa;
logio->port_id[1] = sp->fcport->d_id.b.area;
logio->port_id[2] = sp->fcport->d_id.b.domain;
logio->vp_index = sp->fcport->vp_idx;
}
static void
qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx)
{
struct qla_hw_data *ha = sp->fcport->vha->hw;
mbx->entry_type = MBX_IOCB_TYPE;;
SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id);
mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
mbx->mb1 = HAS_EXTENDED_IDS(ha) ?
cpu_to_le16(sp->fcport->loop_id):
cpu_to_le16(sp->fcport->loop_id << 8);
mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain);
mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 |
sp->fcport->d_id.b.al_pa);
mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx);
/* Implicit: mbx->mbx10 = 0. */
}
int
qla2x00_start_sp(srb_t *sp)
{
int rval;
struct qla_hw_data *ha = sp->fcport->vha->hw;
void *pkt;
struct srb_ctx *ctx = sp->ctx;
unsigned long flags;
rval = QLA_FUNCTION_FAILED;
spin_lock_irqsave(&ha->hardware_lock, flags);
pkt = qla2x00_alloc_iocbs(sp);
if (!pkt)
goto done;
rval = QLA_SUCCESS;
switch (ctx->type) {
case SRB_LOGIN_CMD:
IS_FWI2_CAPABLE(ha) ?
qla24xx_login_iocb(sp, pkt):
qla2x00_login_iocb(sp, pkt);
break;
case SRB_LOGOUT_CMD:
IS_FWI2_CAPABLE(ha) ?
qla24xx_logout_iocb(sp, pkt):
qla2x00_logout_iocb(sp, pkt);
break;
default:
break;
}
wmb();
qla2x00_start_iocbs(sp);
done:
spin_unlock_irqrestore(&ha->hardware_lock, flags);
return rval;
}
......@@ -919,6 +919,249 @@ qla2x00_process_completed_request(struct scsi_qla_host *vha,
}
}
static srb_t *
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
struct req_que *req, void *iocb)
{
struct qla_hw_data *ha = vha->hw;
sts_entry_t *pkt = iocb;
srb_t *sp = NULL;
uint16_t index;
index = LSW(pkt->handle);
if (index >= MAX_OUTSTANDING_COMMANDS) {
qla_printk(KERN_WARNING, ha,
"%s: Invalid completion handle (%x).\n", func, index);
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
goto done;
}
sp = req->outstanding_cmds[index];
if (!sp) {
qla_printk(KERN_WARNING, ha,
"%s: Invalid completion handle (%x) -- timed-out.\n", func,
index);
return sp;
}
if (sp->handle != index) {
qla_printk(KERN_WARNING, ha,
"%s: SRB handle (%x) mismatch %x.\n", func, sp->handle,
index);
return NULL;
}
req->outstanding_cmds[index] = NULL;
done:
return sp;
}
static void
qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
struct mbx_entry *mbx)
{
const char func[] = "MBX-IOCB";
const char *type;
struct qla_hw_data *ha = vha->hw;
fc_port_t *fcport;
srb_t *sp;
struct srb_logio *lio;
uint16_t data[2];
sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
if (!sp)
return;
type = NULL;
lio = sp->ctx;
switch (lio->ctx.type) {
case SRB_LOGIN_CMD:
type = "login";
break;
case SRB_LOGOUT_CMD:
type = "logout";
break;
default:
qla_printk(KERN_WARNING, ha,
"%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
lio->ctx.type);
return;
}
del_timer(&lio->ctx.timer);
fcport = sp->fcport;
data[0] = data[1] = 0;
if (mbx->entry_status) {
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s error entry - entry-status=%x "
"status=%x state-flag=%x status-flags=%x.\n",
fcport->vha->host_no, sp->handle, type,
mbx->entry_status, le16_to_cpu(mbx->status),
le16_to_cpu(mbx->state_flags),
le16_to_cpu(mbx->status_flags)));
DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));
data[0] = MBS_COMMAND_ERROR;
data[1] = lio->flags & SRB_LOGIN_RETRIED ?
QLA_LOGIO_LOGIN_RETRIED: 0;
goto done_post_logio_done_work;
}
if (!mbx->status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
DEBUG2(printk(KERN_DEBUG
"scsi(%ld:%x): Async-%s complete - mbx1=%x.\n",
fcport->vha->host_no, sp->handle, type,
le16_to_cpu(mbx->mb1)));
data[0] = MBS_COMMAND_COMPLETE;
if (lio->ctx.type == SRB_LOGIN_CMD && le16_to_cpu(mbx->mb1) & BIT_1)
fcport->flags |= FCF_TAPE_PRESENT;
goto done_post_logio_done_work;
}
data[0] = le16_to_cpu(mbx->mb0);
switch (data[0]) {
case MBS_PORT_ID_USED:
data[1] = le16_to_cpu(mbx->mb1);
break;
case MBS_LOOP_ID_USED:
break;
default:
data[0] = MBS_COMMAND_ERROR;
data[1] = lio->flags & SRB_LOGIN_RETRIED ?
QLA_LOGIO_LOGIN_RETRIED: 0;
break;
}
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s failed - status=%x mb0=%x mb1=%x mb2=%x "
"mb6=%x mb7=%x.\n",
fcport->vha->host_no, sp->handle, type, le16_to_cpu(mbx->status),
le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
le16_to_cpu(mbx->mb7)));
done_post_logio_done_work:
lio->ctx.type == SRB_LOGIN_CMD ?
qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
lio->ctx.free(sp);
}
static void
qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
struct logio_entry_24xx *logio)
{
const char func[] = "LOGIO-IOCB";
const char *type;
struct qla_hw_data *ha = vha->hw;
fc_port_t *fcport;
srb_t *sp;
struct srb_logio *lio;
uint16_t data[2];
uint32_t iop[2];
sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
if (!sp)
return;
type = NULL;
lio = sp->ctx;
switch (lio->ctx.type) {
case SRB_LOGIN_CMD:
type = "login";
break;
case SRB_LOGOUT_CMD:
type = "logout";
break;
default:
qla_printk(KERN_WARNING, ha,
"%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
lio->ctx.type);
return;
}
del_timer(&lio->ctx.timer);
fcport = sp->fcport;
data[0] = data[1] = 0;
if (logio->entry_status) {
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
fcport->vha->host_no, sp->handle, type,
logio->entry_status));
DEBUG2(qla2x00_dump_buffer((uint8_t *)logio, sizeof(*logio)));
data[0] = MBS_COMMAND_ERROR;
data[1] = lio->flags & SRB_LOGIN_RETRIED ?
QLA_LOGIO_LOGIN_RETRIED: 0;
goto done_post_logio_done_work;
}
if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
DEBUG2(printk(KERN_DEBUG
"scsi(%ld:%x): Async-%s complete - iop0=%x.\n",
fcport->vha->host_no, sp->handle, type,
le32_to_cpu(logio->io_parameter[0])));
data[0] = MBS_COMMAND_COMPLETE;
if (lio->ctx.type == SRB_LOGOUT_CMD)
goto done_post_logio_done_work;
iop[0] = le32_to_cpu(logio->io_parameter[0]);
if (iop[0] & BIT_4) {
fcport->port_type = FCT_TARGET;
if (iop[0] & BIT_8)
fcport->flags |= FCF_TAPE_PRESENT;
}
if (iop[0] & BIT_5)
fcport->port_type = FCT_INITIATOR;
if (logio->io_parameter[7] || logio->io_parameter[8])
fcport->supported_classes |= FC_COS_CLASS2;
if (logio->io_parameter[9] || logio->io_parameter[10])
fcport->supported_classes |= FC_COS_CLASS3;
goto done_post_logio_done_work;
}
iop[0] = le32_to_cpu(logio->io_parameter[0]);
iop[1] = le32_to_cpu(logio->io_parameter[1]);
switch (iop[0]) {
case LSC_SCODE_PORTID_USED:
data[0] = MBS_PORT_ID_USED;
data[1] = LSW(iop[1]);
break;
case LSC_SCODE_NPORT_USED:
data[0] = MBS_LOOP_ID_USED;
break;
case LSC_SCODE_CMD_FAILED:
if ((iop[1] & 0xff) == 0x05) {
data[0] = MBS_NOT_LOGGED_IN;
break;
}
/* Fall through. */
default:
data[0] = MBS_COMMAND_ERROR;
data[1] = lio->flags & SRB_LOGIN_RETRIED ?
QLA_LOGIO_LOGIN_RETRIED: 0;
break;
}
DEBUG2(printk(KERN_WARNING
"scsi(%ld:%x): Async-%s failed - comp=%x iop0=%x iop1=%x.\n",
fcport->vha->host_no, sp->handle, type,
le16_to_cpu(logio->comp_status),
le32_to_cpu(logio->io_parameter[0]),
le32_to_cpu(logio->io_parameter[1])));
done_post_logio_done_work:
lio->ctx.type == SRB_LOGIN_CMD ?
qla2x00_post_async_login_done_work(fcport->vha, fcport, data):
qla2x00_post_async_logout_done_work(fcport->vha, fcport, data);
lio->ctx.free(sp);
}
/**
* qla2x00_process_response_queue() - Process response queue entries.
* @ha: SCSI driver HA context
......@@ -980,6 +1223,9 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
case STATUS_CONT_TYPE:
qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
break;
case MBX_IOCB_TYPE:
qla2x00_mbx_iocb_entry(vha, rsp->req,
(struct mbx_entry *)pkt);
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
......@@ -1590,6 +1836,10 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
qla24xx_report_id_acquisition(vha,
(struct vp_rpt_id_entry_24xx *)pkt);
break;
case LOGINOUT_PORT_IOCB_TYPE:
qla24xx_logio_entry(vha, rsp->req,
(struct logio_entry_24xx *)pkt);
break;
default:
/* Type Not Supported. */
DEBUG4(printk(KERN_WARNING
......
......@@ -253,6 +253,8 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha)
if (!(ha->current_topology & ISP_CFG_F))
return 0;
qla2x00_do_work(vha);
if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) {
/* VP acquired. complete port configuration */
if (atomic_read(&base_vha->loop_state) == LOOP_READY) {
......
......@@ -1170,6 +1170,7 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
int que, cnt;
unsigned long flags;
srb_t *sp;
struct srb_ctx *ctx;
struct qla_hw_data *ha = vha->hw;
struct req_que *req;
......@@ -1182,8 +1183,14 @@ qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res)
sp = req->outstanding_cmds[cnt];
if (sp) {
req->outstanding_cmds[cnt] = NULL;
sp->cmd->result = res;
qla2x00_sp_compl(ha, sp);
if (!sp->ctx) {
sp->cmd->result = res;
qla2x00_sp_compl(ha, sp);
} else {
ctx = sp->ctx;
del_timer_sync(&ctx->timer);
ctx->free(sp);
}
}
}
}
......@@ -2618,7 +2625,31 @@ qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb)
return qla2x00_post_work(vha, e);
}
static void
#define qla2x00_post_async_work(name, type) \
int qla2x00_post_async_##name##_work( \
struct scsi_qla_host *vha, \
fc_port_t *fcport, uint16_t *data) \
{ \
struct qla_work_evt *e; \
\
e = qla2x00_alloc_work(vha, type); \
if (!e) \
return QLA_FUNCTION_FAILED; \
\
e->u.logio.fcport = fcport; \
if (data) { \
e->u.logio.data[0] = data[0]; \
e->u.logio.data[1] = data[1]; \
} \
return qla2x00_post_work(vha, e); \
}
qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN);
qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE);
qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT);
qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE);
void
qla2x00_do_work(struct scsi_qla_host *vha)
{
struct qla_work_evt *e, *tmp;
......@@ -2640,6 +2671,21 @@ qla2x00_do_work(struct scsi_qla_host *vha)
case QLA_EVT_IDC_ACK:
qla81xx_idc_ack(vha, e->u.idc_ack.mb);
break;
case QLA_EVT_ASYNC_LOGIN:
qla2x00_async_login(vha, e->u.logio.fcport,
e->u.logio.data);
break;
case QLA_EVT_ASYNC_LOGIN_DONE:
qla2x00_async_login_done(vha, e->u.logio.fcport,
e->u.logio.data);
break;
case QLA_EVT_ASYNC_LOGOUT:
qla2x00_async_logout(vha, e->u.logio.fcport);
break;
case QLA_EVT_ASYNC_LOGOUT_DONE:
qla2x00_async_logout_done(vha, e->u.logio.fcport,
e->u.logio.data);
break;
}
if (e->flags & QLA_EVT_FLAG_FREE)
kfree(e);
......@@ -2655,6 +2701,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
int status;
uint16_t next_loopid = 0;
struct qla_hw_data *ha = vha->hw;
uint16_t data[2];
list_for_each_entry(fcport, &vha->vp_fcports, list) {
/*
......@@ -2664,6 +2711,7 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
if (atomic_read(&fcport->state) !=
FCS_ONLINE && fcport->login_retry) {
fcport->login_retry--;
if (fcport->flags & FCF_FABRIC_DEVICE) {
if (fcport->flags & FCF_TAPE_PRESENT)
ha->isp_ops->fabric_logout(vha,
......@@ -2672,13 +2720,22 @@ void qla2x00_relogin(struct scsi_qla_host *vha)
fcport->d_id.b.area,
fcport->d_id.b.al_pa);
status = qla2x00_fabric_login(vha, fcport,
&next_loopid);
if (IS_ALOGIO_CAPABLE(ha)) {
data[0] = 0;
data[1] = QLA_LOGIO_LOGIN_RETRIED;
status = qla2x00_post_async_login_work(
vha, fcport, data);
if (status == QLA_SUCCESS)
continue;
/* Attempt a retry. */
status = 1;
} else
status = qla2x00_fabric_login(vha,
fcport, &next_loopid);
} else
status = qla2x00_local_device_login(vha,
fcport);
fcport->login_retry--;
if (status == QLA_SUCCESS) {
fcport->old_loop_id = fcport->loop_id;
......@@ -2851,6 +2908,9 @@ qla2x00_do_dpc(void *data)
*/
ha->dpc_active = 0;
/* Cleanup any residual CTX SRBs. */
qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16);
return 0;
}
......
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