Skip to content

Commit

Permalink
[SCSI] qla2xxx: Add asynchronous-login support.
Browse files Browse the repository at this point in the history
ISPs which support this feature include 23xx and above.

Signed-off-by: Andrew Vasquez <[email protected]>
Signed-off-by: Giridhar Malavali <[email protected]>
Signed-off-by: James Bottomley <[email protected]>
  • Loading branch information
avasquez01 authored and James Bottomley committed Sep 5, 2009
1 parent cf53b06 commit ac280b6
Show file tree
Hide file tree
Showing 7 changed files with 784 additions and 9 deletions.
32 changes: 32 additions & 0 deletions drivers/scsi/qla2xxx/qla_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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,
};


Expand All @@ -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;
};

Expand Down Expand Up @@ -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)
Expand Down
20 changes: 20 additions & 0 deletions drivers/scsi/qla2xxx/qla_gbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand All @@ -76,13 +84,24 @@ 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 *);
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.
*/
Expand Down Expand Up @@ -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.
Expand Down
215 changes: 212 additions & 3 deletions drivers/scsi/qla2xxx/qla_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
/****************************************************************************/
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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.*/
Expand Down
Loading

0 comments on commit ac280b6

Please sign in to comment.