2005-04-16 16:20:36 -06:00
|
|
|
/*
|
2005-10-27 12:10:08 -06:00
|
|
|
* QLogic Fibre Channel HBA Driver
|
2008-04-03 14:13:13 -06:00
|
|
|
* Copyright (c) 2003-2008 QLogic Corporation
|
2005-04-16 16:20:36 -06:00
|
|
|
*
|
2005-10-27 12:10:08 -06:00
|
|
|
* See LICENSE.qla2xxx for copyright and licensing details.
|
2005-04-16 16:20:36 -06:00
|
|
|
*/
|
|
|
|
#include "qla_def.h"
|
2008-12-09 17:45:39 -07:00
|
|
|
#include "qla_gbl.h"
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
#include <linux/delay.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 02:04:11 -06:00
|
|
|
#include <linux/slab.h>
|
2005-07-06 11:31:37 -06:00
|
|
|
#include <linux/vmalloc.h>
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
#include "qla_devtbl.h"
|
|
|
|
|
2007-04-16 13:37:43 -06:00
|
|
|
#ifdef CONFIG_SPARC
|
|
|
|
#include <asm/prom.h>
|
|
|
|
#endif
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/*
|
|
|
|
* QLogic ISP2x00 Hardware Support Function Prototypes.
|
|
|
|
*/
|
|
|
|
static int qla2x00_isp_firmware(scsi_qla_host_t *);
|
|
|
|
static int qla2x00_setup_chip(scsi_qla_host_t *);
|
|
|
|
static int qla2x00_init_rings(scsi_qla_host_t *);
|
|
|
|
static int qla2x00_fw_ready(scsi_qla_host_t *);
|
|
|
|
static int qla2x00_configure_hba(scsi_qla_host_t *);
|
|
|
|
static int qla2x00_configure_loop(scsi_qla_host_t *);
|
|
|
|
static int qla2x00_configure_local_loop(scsi_qla_host_t *);
|
|
|
|
static int qla2x00_configure_fabric(scsi_qla_host_t *);
|
|
|
|
static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);
|
|
|
|
static int qla2x00_device_resync(scsi_qla_host_t *);
|
|
|
|
static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
|
|
|
|
uint16_t *);
|
|
|
|
|
|
|
|
static int qla2x00_restart_isp(scsi_qla_host_t *);
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
static int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
|
2006-06-30 03:33:06 -06:00
|
|
|
|
2008-04-03 14:13:26 -06:00
|
|
|
static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
|
|
|
|
static int qla84xx_init_chip(scsi_qla_host_t *);
|
2008-12-09 17:45:39 -07:00
|
|
|
static int qla25xx_init_queues(struct qla_hw_data *);
|
2008-04-03 14:13:26 -06:00
|
|
|
|
2009-08-20 12:06:05 -06:00
|
|
|
/* SRB Extensions ---------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
|
|
|
qla2x00_ctx_sp_timeout(unsigned long __data)
|
|
|
|
{
|
|
|
|
srb_t *sp = (srb_t *)__data;
|
|
|
|
struct srb_ctx *ctx;
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_iocb *iocb;
|
2009-08-20 12:06:05 -06:00
|
|
|
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;
|
2010-05-04 16:01:28 -06:00
|
|
|
iocb = ctx->u.iocb_cmd;
|
|
|
|
iocb->timeout(sp);
|
2009-08-20 12:06:05 -06:00
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
iocb->free(sp);
|
2009-08-20 12:06:05 -06:00
|
|
|
}
|
|
|
|
|
2010-01-12 14:02:47 -07:00
|
|
|
void
|
2009-08-20 12:06:05 -06:00
|
|
|
qla2x00_ctx_sp_free(srb_t *sp)
|
|
|
|
{
|
|
|
|
struct srb_ctx *ctx = sp->ctx;
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_iocb *iocb = ctx->u.iocb_cmd;
|
2009-08-20 12:06:05 -06:00
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
del_timer_sync(&iocb->timer);
|
|
|
|
kfree(iocb);
|
2009-08-20 12:06:05 -06:00
|
|
|
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;
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_iocb *iocb;
|
2009-08-20 12:06:05 -06:00
|
|
|
|
|
|
|
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);
|
2010-05-04 16:01:28 -06:00
|
|
|
sp = NULL;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
iocb = kzalloc(sizeof(struct srb_iocb), GFP_KERNEL);
|
|
|
|
if (!iocb) {
|
|
|
|
mempool_free(sp, ha->srb_mempool);
|
|
|
|
sp = NULL;
|
|
|
|
kfree(ctx);
|
2009-08-20 12:06:05 -06:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(sp, 0, sizeof(*sp));
|
|
|
|
sp->fcport = fcport;
|
|
|
|
sp->ctx = ctx;
|
2010-05-04 16:01:28 -06:00
|
|
|
ctx->u.iocb_cmd = iocb;
|
|
|
|
iocb->free = qla2x00_ctx_sp_free;
|
2009-08-20 12:06:05 -06:00
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
init_timer(&iocb->timer);
|
2009-08-20 12:06:05 -06:00
|
|
|
if (!tmo)
|
|
|
|
goto done;
|
2010-05-04 16:01:28 -06:00
|
|
|
iocb->timer.expires = jiffies + tmo * HZ;
|
|
|
|
iocb->timer.data = (unsigned long)sp;
|
|
|
|
iocb->timer.function = qla2x00_ctx_sp_timeout;
|
|
|
|
add_timer(&iocb->timer);
|
2009-08-20 12:06:05 -06:00
|
|
|
done:
|
|
|
|
return sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Asynchronous Login/Logout Routines -------------------------------------- */
|
|
|
|
|
|
|
|
#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
|
|
|
|
|
|
|
|
static void
|
2010-05-04 16:01:29 -06:00
|
|
|
qla2x00_async_iocb_timeout(srb_t *sp)
|
2009-08-20 12:06:05 -06:00
|
|
|
{
|
|
|
|
fc_port_t *fcport = sp->fcport;
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_ctx *ctx = sp->ctx;
|
2009-08-20 12:06:05 -06:00
|
|
|
|
|
|
|
DEBUG2(printk(KERN_WARNING
|
|
|
|
"scsi(%ld:%x): Async-%s timeout.\n",
|
2010-05-04 16:01:28 -06:00
|
|
|
fcport->vha->host_no, sp->handle, ctx->name));
|
2009-08-20 12:06:05 -06:00
|
|
|
|
2010-05-04 16:01:26 -06:00
|
|
|
fcport->flags &= ~FCF_ASYNC_SENT;
|
2010-05-04 16:01:28 -06:00
|
|
|
if (ctx->type == SRB_LOGIN_CMD)
|
2009-08-20 12:06:05 -06:00
|
|
|
qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
|
|
|
|
}
|
|
|
|
|
2010-05-04 16:01:25 -06:00
|
|
|
static void
|
|
|
|
qla2x00_async_login_ctx_done(srb_t *sp)
|
|
|
|
{
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_ctx *ctx = sp->ctx;
|
|
|
|
struct srb_iocb *lio = ctx->u.iocb_cmd;
|
2010-05-04 16:01:25 -06:00
|
|
|
|
|
|
|
qla2x00_post_async_login_done_work(sp->fcport->vha, sp->fcport,
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->u.logio.data);
|
|
|
|
lio->free(sp);
|
2010-05-04 16:01:25 -06:00
|
|
|
}
|
|
|
|
|
2009-08-20 12:06:05 -06:00
|
|
|
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;
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_ctx *ctx;
|
|
|
|
struct srb_iocb *lio;
|
2009-08-20 12:06:05 -06:00
|
|
|
int rval;
|
|
|
|
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
2010-05-04 16:01:28 -06:00
|
|
|
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
|
2009-08-20 12:06:05 -06:00
|
|
|
ELS_TMO_2_RATOV(ha) + 2);
|
|
|
|
if (!sp)
|
|
|
|
goto done;
|
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
ctx = sp->ctx;
|
|
|
|
ctx->type = SRB_LOGIN_CMD;
|
|
|
|
ctx->name = "login";
|
|
|
|
lio = ctx->u.iocb_cmd;
|
2010-05-04 16:01:29 -06:00
|
|
|
lio->timeout = qla2x00_async_iocb_timeout;
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->done = qla2x00_async_login_ctx_done;
|
|
|
|
lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
|
2009-08-20 12:06:05 -06:00
|
|
|
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->u.logio.flags |= SRB_LOGIN_RETRIED;
|
2009-08-20 12:06:05 -06:00
|
|
|
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:
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->free(sp);
|
2009-08-20 12:06:05 -06:00
|
|
|
done:
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2010-05-04 16:01:25 -06:00
|
|
|
static void
|
|
|
|
qla2x00_async_logout_ctx_done(srb_t *sp)
|
|
|
|
{
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_ctx *ctx = sp->ctx;
|
|
|
|
struct srb_iocb *lio = ctx->u.iocb_cmd;
|
2010-05-04 16:01:25 -06:00
|
|
|
|
|
|
|
qla2x00_post_async_logout_done_work(sp->fcport->vha, sp->fcport,
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->u.logio.data);
|
|
|
|
lio->free(sp);
|
2010-05-04 16:01:25 -06:00
|
|
|
}
|
|
|
|
|
2009-08-20 12:06:05 -06:00
|
|
|
int
|
|
|
|
qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
|
|
|
|
{
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
srb_t *sp;
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_ctx *ctx;
|
|
|
|
struct srb_iocb *lio;
|
2009-08-20 12:06:05 -06:00
|
|
|
int rval;
|
|
|
|
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
2010-05-04 16:01:28 -06:00
|
|
|
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
|
2009-08-20 12:06:05 -06:00
|
|
|
ELS_TMO_2_RATOV(ha) + 2);
|
|
|
|
if (!sp)
|
|
|
|
goto done;
|
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
ctx = sp->ctx;
|
|
|
|
ctx->type = SRB_LOGOUT_CMD;
|
|
|
|
ctx->name = "logout";
|
|
|
|
lio = ctx->u.iocb_cmd;
|
2010-05-04 16:01:29 -06:00
|
|
|
lio->timeout = qla2x00_async_iocb_timeout;
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->done = qla2x00_async_logout_ctx_done;
|
2009-08-20 12:06:05 -06:00
|
|
|
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:
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->free(sp);
|
2009-08-20 12:06:05 -06:00
|
|
|
done:
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2010-05-04 16:01:26 -06:00
|
|
|
static void
|
|
|
|
qla2x00_async_adisc_ctx_done(srb_t *sp)
|
|
|
|
{
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_ctx *ctx = sp->ctx;
|
|
|
|
struct srb_iocb *lio = ctx->u.iocb_cmd;
|
2010-05-04 16:01:26 -06:00
|
|
|
|
|
|
|
qla2x00_post_async_adisc_done_work(sp->fcport->vha, sp->fcport,
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->u.logio.data);
|
|
|
|
lio->free(sp);
|
2010-05-04 16:01:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
|
|
|
|
uint16_t *data)
|
|
|
|
{
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
srb_t *sp;
|
2010-05-04 16:01:28 -06:00
|
|
|
struct srb_ctx *ctx;
|
|
|
|
struct srb_iocb *lio;
|
2010-05-04 16:01:26 -06:00
|
|
|
int rval;
|
|
|
|
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
2010-05-04 16:01:28 -06:00
|
|
|
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
|
2010-05-04 16:01:26 -06:00
|
|
|
ELS_TMO_2_RATOV(ha) + 2);
|
|
|
|
if (!sp)
|
|
|
|
goto done;
|
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
ctx = sp->ctx;
|
|
|
|
ctx->type = SRB_ADISC_CMD;
|
|
|
|
ctx->name = "adisc";
|
|
|
|
lio = ctx->u.iocb_cmd;
|
2010-05-04 16:01:29 -06:00
|
|
|
lio->timeout = qla2x00_async_iocb_timeout;
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->done = qla2x00_async_adisc_ctx_done;
|
2010-05-04 16:01:26 -06:00
|
|
|
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->u.logio.flags |= SRB_LOGIN_RETRIED;
|
2010-05-04 16:01:26 -06:00
|
|
|
rval = qla2x00_start_sp(sp);
|
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
goto done_free_sp;
|
|
|
|
|
|
|
|
DEBUG2(printk(KERN_DEBUG
|
|
|
|
"scsi(%ld:%x): Async-adisc - 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:
|
2010-05-04 16:01:28 -06:00
|
|
|
lio->free(sp);
|
2010-05-04 16:01:26 -06:00
|
|
|
done:
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2010-05-04 16:01:29 -06:00
|
|
|
static void
|
|
|
|
qla2x00_async_tm_cmd_ctx_done(srb_t *sp)
|
|
|
|
{
|
|
|
|
struct srb_ctx *ctx = sp->ctx;
|
|
|
|
struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;
|
|
|
|
|
|
|
|
qla2x00_async_tm_cmd_done(sp->fcport->vha, sp->fcport, iocb);
|
|
|
|
iocb->free(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
|
|
|
|
uint32_t tag)
|
|
|
|
{
|
|
|
|
struct scsi_qla_host *vha = fcport->vha;
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
srb_t *sp;
|
|
|
|
struct srb_ctx *ctx;
|
|
|
|
struct srb_iocb *tcf;
|
|
|
|
int rval;
|
|
|
|
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
|
|
|
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
|
|
|
|
ELS_TMO_2_RATOV(ha) + 2);
|
|
|
|
if (!sp)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
ctx = sp->ctx;
|
|
|
|
ctx->type = SRB_TM_CMD;
|
|
|
|
ctx->name = "tmf";
|
|
|
|
tcf = ctx->u.iocb_cmd;
|
|
|
|
tcf->u.tmf.flags = flags;
|
|
|
|
tcf->u.tmf.lun = lun;
|
|
|
|
tcf->u.tmf.data = tag;
|
|
|
|
tcf->timeout = qla2x00_async_iocb_timeout;
|
|
|
|
tcf->done = qla2x00_async_tm_cmd_ctx_done;
|
|
|
|
|
|
|
|
rval = qla2x00_start_sp(sp);
|
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
goto done_free_sp;
|
|
|
|
|
|
|
|
DEBUG2(printk(KERN_DEBUG
|
|
|
|
"scsi(%ld:%x): Async-tmf - 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:
|
|
|
|
tcf->free(sp);
|
|
|
|
done:
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
qla2x00_async_marker_ctx_done(srb_t *sp)
|
|
|
|
{
|
|
|
|
struct srb_ctx *ctx = sp->ctx;
|
|
|
|
struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;
|
|
|
|
|
|
|
|
qla2x00_async_marker_done(sp->fcport->vha, sp->fcport, iocb);
|
|
|
|
iocb->free(sp);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
qla2x00_async_marker(fc_port_t *fcport, uint16_t lun, uint8_t modif)
|
|
|
|
{
|
|
|
|
struct scsi_qla_host *vha = fcport->vha;
|
|
|
|
srb_t *sp;
|
|
|
|
struct srb_ctx *ctx;
|
|
|
|
struct srb_iocb *mrk;
|
|
|
|
int rval;
|
|
|
|
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
|
|
|
sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), 0);
|
|
|
|
if (!sp)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
ctx = sp->ctx;
|
|
|
|
ctx->type = SRB_MARKER_CMD;
|
|
|
|
ctx->name = "marker";
|
|
|
|
mrk = ctx->u.iocb_cmd;
|
|
|
|
mrk->u.marker.lun = lun;
|
|
|
|
mrk->u.marker.modif = modif;
|
|
|
|
mrk->timeout = qla2x00_async_iocb_timeout;
|
|
|
|
mrk->done = qla2x00_async_marker_ctx_done;
|
|
|
|
|
|
|
|
rval = qla2x00_start_sp(sp);
|
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
goto done_free_sp;
|
|
|
|
|
|
|
|
DEBUG2(printk(KERN_DEBUG
|
|
|
|
"scsi(%ld:%x): Async-marker - 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:
|
|
|
|
mrk->free(sp);
|
|
|
|
done:
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
void
|
2009-08-20 12:06:05 -06:00
|
|
|
qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
|
|
|
|
uint16_t *data)
|
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
|
|
|
|
switch (data[0]) {
|
|
|
|
case MBS_COMMAND_COMPLETE:
|
2010-05-04 16:01:25 -06:00
|
|
|
if (fcport->flags & FCF_FCP2_DEVICE) {
|
2010-05-04 16:01:26 -06:00
|
|
|
fcport->flags |= FCF_ASYNC_SENT;
|
|
|
|
qla2x00_post_async_adisc_work(vha, fcport, data);
|
|
|
|
break;
|
2010-05-04 16:01:25 -06:00
|
|
|
}
|
|
|
|
qla2x00_update_fcport(vha, fcport);
|
2009-08-20 12:06:05 -06:00
|
|
|
break;
|
|
|
|
case MBS_COMMAND_ERROR:
|
2010-05-04 16:01:26 -06:00
|
|
|
fcport->flags &= ~FCF_ASYNC_SENT;
|
2009-08-20 12:06:05 -06:00
|
|
|
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) {
|
2010-05-04 16:01:26 -06:00
|
|
|
fcport->flags &= ~FCF_ASYNC_SENT;
|
2009-08-20 12:06:05 -06:00
|
|
|
qla2x00_mark_device_lost(vha, fcport, 1, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
qla2x00_post_async_login_work(vha, fcport, NULL);
|
|
|
|
break;
|
|
|
|
}
|
2010-05-04 16:01:28 -06:00
|
|
|
return;
|
2009-08-20 12:06:05 -06:00
|
|
|
}
|
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
void
|
2009-08-20 12:06:05 -06:00
|
|
|
qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
|
|
|
|
uint16_t *data)
|
|
|
|
{
|
|
|
|
qla2x00_mark_device_lost(vha, fcport, 1, 0);
|
2010-05-04 16:01:28 -06:00
|
|
|
return;
|
2009-08-20 12:06:05 -06:00
|
|
|
}
|
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
void
|
2010-05-04 16:01:26 -06:00
|
|
|
qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
|
|
|
|
uint16_t *data)
|
|
|
|
{
|
|
|
|
if (data[0] == MBS_COMMAND_COMPLETE) {
|
|
|
|
qla2x00_update_fcport(vha, fcport);
|
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
return;
|
2010-05-04 16:01:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Retry login. */
|
|
|
|
fcport->flags &= ~FCF_ASYNC_SENT;
|
|
|
|
if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
|
|
|
|
set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
|
|
|
|
else
|
|
|
|
qla2x00_mark_device_lost(vha, fcport, 1, 0);
|
|
|
|
|
2010-05-04 16:01:28 -06:00
|
|
|
return;
|
2010-05-04 16:01:26 -06:00
|
|
|
}
|
|
|
|
|
2010-05-04 16:01:29 -06:00
|
|
|
void
|
|
|
|
qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport,
|
|
|
|
struct srb_iocb *iocb)
|
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
uint32_t flags;
|
|
|
|
uint16_t lun;
|
|
|
|
|
|
|
|
flags = iocb->u.tmf.flags;
|
|
|
|
lun = (uint16_t)iocb->u.tmf.lun;
|
|
|
|
|
|
|
|
/* Issue Marker IOCB */
|
|
|
|
rval = qla2x00_async_marker(fcport, lun,
|
|
|
|
flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
|
|
|
|
|
|
|
|
if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
|
|
|
|
DEBUG2_3_11(printk(KERN_WARNING
|
|
|
|
"%s(%ld): TM IOCB failed (%x).\n",
|
|
|
|
__func__, vha->host_no, rval));
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
qla2x00_async_marker_done(struct scsi_qla_host *vha, fc_port_t *fcport,
|
|
|
|
struct srb_iocb *iocb)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Currently we dont have any specific post response processing
|
|
|
|
* for this IOCB. We'll just return success or failed
|
|
|
|
* depending on whether the IOCB command succeeded or failed.
|
|
|
|
*/
|
|
|
|
if (iocb->u.tmf.data) {
|
|
|
|
DEBUG2_3_11(printk(KERN_WARNING
|
|
|
|
"%s(%ld): Marker IOCB failed (%x).\n",
|
|
|
|
__func__, vha->host_no, iocb->u.tmf.data));
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/****************************************************************************/
|
|
|
|
/* QLogic ISP2x00 Hardware Support Functions. */
|
|
|
|
/****************************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_initialize_adapter
|
|
|
|
* Initialize board.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success
|
|
|
|
*/
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_initialize_adapter(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
2009-03-24 10:08:07 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Clear adapter flags. */
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.online = 0;
|
2009-03-24 10:08:07 -06:00
|
|
|
ha->flags.chip_reset_done = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.reset_active = 0;
|
2009-12-15 22:29:46 -07:00
|
|
|
ha->flags.pci_channel_io_perm_failure = 0;
|
|
|
|
ha->flags.eeh_busy = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
|
|
|
|
atomic_set(&vha->loop_state, LOOP_DOWN);
|
|
|
|
vha->device_flags = DFLG_NO_CABLE;
|
|
|
|
vha->dpc_flags = 0;
|
|
|
|
vha->flags.management_server_logged_in = 0;
|
|
|
|
vha->marker_needed = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->isp_abort_cnt = 0;
|
|
|
|
ha->beacon_blink_led = 0;
|
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
set_bit(0, ha->req_qid_map);
|
|
|
|
set_bit(0, ha->rsp_qid_map);
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = ha->isp_ops->pci_config(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval) {
|
2007-01-29 11:22:29 -07:00
|
|
|
DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->reset_chip(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2xxx_get_flash_info(vha);
|
2008-09-11 22:22:49 -06:00
|
|
|
if (rval) {
|
|
|
|
DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2008-09-11 22:22:49 -06:00
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
ha->isp_ops->get_flash_version(vha, req->ring);
|
2007-01-29 11:22:21 -07:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->nvram_config(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2006-06-23 17:10:39 -06:00
|
|
|
if (ha->flags.disable_serdes) {
|
|
|
|
/* Mask HBA via NVRAM settings? */
|
|
|
|
qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
|
|
|
|
"%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->port_name[0], vha->port_name[1],
|
|
|
|
vha->port_name[2], vha->port_name[3],
|
|
|
|
vha->port_name[4], vha->port_name[5],
|
|
|
|
vha->port_name[6], vha->port_name[7]);
|
2006-06-23 17:10:39 -06:00
|
|
|
return QLA_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) {
|
|
|
|
rval = ha->isp_ops->chip_diag(vha);
|
2006-11-22 09:22:19 -07:00
|
|
|
if (rval)
|
|
|
|
return (rval);
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_setup_chip(vha);
|
2006-11-22 09:22:19 -07:00
|
|
|
if (rval)
|
|
|
|
return (rval);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2010-04-12 18:59:55 -06:00
|
|
|
|
2008-04-03 14:13:26 -06:00
|
|
|
if (IS_QLA84XX(ha)) {
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->cs84xx = qla84xx_get_chip(vha);
|
2008-04-03 14:13:26 -06:00
|
|
|
if (!ha->cs84xx) {
|
|
|
|
qla_printk(KERN_ERR, ha,
|
|
|
|
"Unable to configure ISP84XX.\n");
|
|
|
|
return QLA_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
}
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_init_rings(vha);
|
2009-03-24 10:08:07 -06:00
|
|
|
ha->flags.chip_reset_done = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2010-01-12 14:02:47 -07:00
|
|
|
if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) {
|
2010-03-19 18:04:02 -06:00
|
|
|
/* Issue verify 84xx FW IOCB to complete 84xx initialization */
|
2010-01-12 14:02:47 -07:00
|
|
|
rval = qla84xx_init_chip(vha);
|
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
qla_printk(KERN_ERR, ha,
|
|
|
|
"Unable to initialize ISP84XX.\n");
|
|
|
|
qla84xx_put_chip(vha);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-19 18:03:59 -06:00
|
|
|
if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) {
|
|
|
|
if (qla24xx_read_fcp_prio_cfg(vha))
|
|
|
|
qla_printk(KERN_ERR, ha,
|
|
|
|
"Unable to read FCP priority data.\n");
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-07-06 11:30:05 -06:00
|
|
|
* qla2100_pci_config() - Setup ISP21xx PCI configuration registers.
|
2005-04-16 16:20:36 -06:00
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
2005-07-06 11:30:05 -06:00
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2100_pci_config(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2007-05-07 08:43:01 -06:00
|
|
|
uint16_t w;
|
2005-07-06 11:30:05 -06:00
|
|
|
unsigned long flags;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:30:26 -06:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
pci_set_master(ha->pdev);
|
2007-07-19 16:06:02 -06:00
|
|
|
pci_try_set_mwi(ha->pdev);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
|
2007-05-07 08:43:01 -06:00
|
|
|
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
|
2005-07-06 11:30:05 -06:00
|
|
|
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
|
|
|
|
|
2008-10-24 16:13:45 -06:00
|
|
|
pci_disable_rom(ha->pdev);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Get PCI bus information. */
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
2005-07-06 11:30:26 -06:00
|
|
|
ha->pci_attr = RD_REG_WORD(®->ctrl_status);
|
2005-04-16 16:20:36 -06:00
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
return QLA_SUCCESS;
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
/**
|
|
|
|
* qla2300_pci_config() - Setup ISP23xx PCI configuration registers.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2300_pci_config(scsi_qla_host_t *vha)
|
2005-07-06 11:30:05 -06:00
|
|
|
{
|
2007-05-07 08:43:01 -06:00
|
|
|
uint16_t w;
|
2005-07-06 11:30:05 -06:00
|
|
|
unsigned long flags = 0;
|
|
|
|
uint32_t cnt;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:30:26 -06:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
pci_set_master(ha->pdev);
|
2007-07-19 16:06:02 -06:00
|
|
|
pci_try_set_mwi(ha->pdev);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
|
2007-05-07 08:43:01 -06:00
|
|
|
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
if (IS_QLA2322(ha) || IS_QLA6322(ha))
|
|
|
|
w &= ~PCI_COMMAND_INTX_DISABLE;
|
2007-05-07 08:43:01 -06:00
|
|
|
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
/*
|
|
|
|
* If this is a 2300 card and not 2312, reset the
|
|
|
|
* COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately,
|
|
|
|
* the 2310 also reports itself as a 2300 so we need to get the
|
|
|
|
* fb revision level -- a 6 indicates it really is a 2300 and
|
|
|
|
* not a 2310.
|
|
|
|
*/
|
|
|
|
if (IS_QLA2300(ha)) {
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
/* Pause RISC. */
|
2005-07-06 11:30:26 -06:00
|
|
|
WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC);
|
2005-07-06 11:30:05 -06:00
|
|
|
for (cnt = 0; cnt < 30000; cnt++) {
|
2005-07-06 11:30:26 -06:00
|
|
|
if ((RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) != 0)
|
2005-07-06 11:30:05 -06:00
|
|
|
break;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
udelay(10);
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
/* Select FPM registers. */
|
2005-07-06 11:30:26 -06:00
|
|
|
WRT_REG_WORD(®->ctrl_status, 0x20);
|
|
|
|
RD_REG_WORD(®->ctrl_status);
|
2005-07-06 11:30:05 -06:00
|
|
|
|
|
|
|
/* Get the fb rev level */
|
2005-07-06 11:30:26 -06:00
|
|
|
ha->fb_rev = RD_FB_CMD_REG(ha, reg);
|
2005-07-06 11:30:05 -06:00
|
|
|
|
|
|
|
if (ha->fb_rev == FPM_2300)
|
2007-05-07 08:43:01 -06:00
|
|
|
pci_clear_mwi(ha->pdev);
|
2005-07-06 11:30:05 -06:00
|
|
|
|
|
|
|
/* Deselect FPM registers. */
|
2005-07-06 11:30:26 -06:00
|
|
|
WRT_REG_WORD(®->ctrl_status, 0x0);
|
|
|
|
RD_REG_WORD(®->ctrl_status);
|
2005-07-06 11:30:05 -06:00
|
|
|
|
|
|
|
/* Release RISC module. */
|
2005-07-06 11:30:26 -06:00
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC);
|
2005-07-06 11:30:05 -06:00
|
|
|
for (cnt = 0; cnt < 30000; cnt++) {
|
2005-07-06 11:30:26 -06:00
|
|
|
if ((RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0)
|
2005-07-06 11:30:05 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
udelay(10);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
|
|
|
|
|
2008-10-24 16:13:45 -06:00
|
|
|
pci_disable_rom(ha->pdev);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
/* Get PCI bus information. */
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
2005-07-06 11:30:26 -06:00
|
|
|
ha->pci_attr = RD_REG_WORD(®->ctrl_status);
|
2005-07-06 11:30:05 -06:00
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
return QLA_SUCCESS;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
/**
|
|
|
|
* qla24xx_pci_config() - Setup ISP24xx PCI configuration registers.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_pci_config(scsi_qla_host_t *vha)
|
2005-07-06 11:31:37 -06:00
|
|
|
{
|
2007-05-07 08:43:01 -06:00
|
|
|
uint16_t w;
|
2005-07-06 11:31:37 -06:00
|
|
|
unsigned long flags = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:31:37 -06:00
|
|
|
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
|
|
|
|
|
|
|
pci_set_master(ha->pdev);
|
2007-07-19 16:06:02 -06:00
|
|
|
pci_try_set_mwi(ha->pdev);
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
|
2007-05-07 08:43:01 -06:00
|
|
|
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
|
2005-07-06 11:31:37 -06:00
|
|
|
w &= ~PCI_COMMAND_INTX_DISABLE;
|
|
|
|
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
|
|
|
|
|
|
|
|
pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
|
|
|
|
|
|
|
|
/* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
|
2007-07-19 16:06:01 -06:00
|
|
|
if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
|
|
|
|
pcix_set_mmrbc(ha->pdev, 2048);
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
/* PCIe -- adjust Maximum Read Request Size (2048). */
|
2007-07-19 16:06:01 -06:00
|
|
|
if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
|
|
|
|
pcie_set_readrq(ha->pdev, 2048);
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2008-10-24 16:13:45 -06:00
|
|
|
pci_disable_rom(ha->pdev);
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2007-06-08 16:46:36 -06:00
|
|
|
ha->chip_revision = ha->pdev->revision;
|
2007-01-29 11:22:19 -07:00
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
/* Get PCI bus information. */
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
ha->pci_attr = RD_REG_DWORD(®->ctrl_status);
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
return QLA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2007-07-19 21:37:34 -06:00
|
|
|
/**
|
|
|
|
* qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla25xx_pci_config(scsi_qla_host_t *vha)
|
2007-07-19 21:37:34 -06:00
|
|
|
{
|
|
|
|
uint16_t w;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2007-07-19 21:37:34 -06:00
|
|
|
|
|
|
|
pci_set_master(ha->pdev);
|
|
|
|
pci_try_set_mwi(ha->pdev);
|
|
|
|
|
|
|
|
pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
|
|
|
|
w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
|
|
|
|
w &= ~PCI_COMMAND_INTX_DISABLE;
|
|
|
|
pci_write_config_word(ha->pdev, PCI_COMMAND, w);
|
|
|
|
|
|
|
|
/* PCIe -- adjust Maximum Read Request Size (2048). */
|
|
|
|
if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
|
|
|
|
pcie_set_readrq(ha->pdev, 2048);
|
|
|
|
|
2008-10-24 16:13:45 -06:00
|
|
|
pci_disable_rom(ha->pdev);
|
2007-07-19 21:37:34 -06:00
|
|
|
|
|
|
|
ha->chip_revision = ha->pdev->revision;
|
|
|
|
|
|
|
|
return QLA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/**
|
|
|
|
* qla2x00_isp_firmware() - Choose firmware image.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_isp_firmware(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
2008-07-10 17:56:01 -06:00
|
|
|
uint16_t loop_id, topo, sw_cap;
|
|
|
|
uint8_t domain, area, al_pa;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Assume loading risc code */
|
2005-07-06 11:32:07 -06:00
|
|
|
rval = QLA_FUNCTION_FAILED;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (ha->flags.disable_risc_code_load) {
|
|
|
|
DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");
|
|
|
|
|
|
|
|
/* Verify checksum of loaded RISC code. */
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_verify_checksum(vha, ha->fw_srisc_address);
|
2008-07-10 17:56:01 -06:00
|
|
|
if (rval == QLA_SUCCESS) {
|
|
|
|
/* And, verify we are not in ROM code. */
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,
|
2008-07-10 17:56:01 -06:00
|
|
|
&area, &domain, &topo, &sw_cap);
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rval) {
|
|
|
|
DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qla2x00_reset_chip() - Reset ISP chip.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
2005-07-06 11:30:05 -06:00
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_reset_chip(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
unsigned long flags = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:30:26 -06:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2005-04-16 16:20:36 -06:00
|
|
|
uint32_t cnt;
|
|
|
|
uint16_t cmd;
|
|
|
|
|
2009-12-15 22:29:46 -07:00
|
|
|
if (unlikely(pci_channel_offline(ha->pdev)))
|
|
|
|
return;
|
|
|
|
|
2007-07-19 16:06:00 -06:00
|
|
|
ha->isp_ops->disable_intrs(ha);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
/* Turn off master enable */
|
|
|
|
cmd = 0;
|
|
|
|
pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd);
|
|
|
|
cmd &= ~PCI_COMMAND_MASTER;
|
|
|
|
pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
|
|
|
|
|
|
|
|
if (!IS_QLA2100(ha)) {
|
|
|
|
/* Pause RISC. */
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC);
|
|
|
|
if (IS_QLA2200(ha) || IS_QLA2300(ha)) {
|
|
|
|
for (cnt = 0; cnt < 30000; cnt++) {
|
|
|
|
if ((RD_REG_WORD(®->hccr) &
|
|
|
|
HCCR_RISC_PAUSE) != 0)
|
|
|
|
break;
|
|
|
|
udelay(100);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
RD_REG_WORD(®->hccr); /* PCI Posting. */
|
|
|
|
udelay(10);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Select FPM registers. */
|
|
|
|
WRT_REG_WORD(®->ctrl_status, 0x20);
|
|
|
|
RD_REG_WORD(®->ctrl_status); /* PCI Posting. */
|
|
|
|
|
|
|
|
/* FPM Soft Reset. */
|
|
|
|
WRT_REG_WORD(®->fpm_diag_config, 0x100);
|
|
|
|
RD_REG_WORD(®->fpm_diag_config); /* PCI Posting. */
|
|
|
|
|
|
|
|
/* Toggle Fpm Reset. */
|
|
|
|
if (!IS_QLA2200(ha)) {
|
|
|
|
WRT_REG_WORD(®->fpm_diag_config, 0x0);
|
|
|
|
RD_REG_WORD(®->fpm_diag_config); /* PCI Posting. */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Select frame buffer registers. */
|
|
|
|
WRT_REG_WORD(®->ctrl_status, 0x10);
|
|
|
|
RD_REG_WORD(®->ctrl_status); /* PCI Posting. */
|
|
|
|
|
|
|
|
/* Reset frame buffer FIFOs. */
|
|
|
|
if (IS_QLA2200(ha)) {
|
|
|
|
WRT_FB_CMD_REG(ha, reg, 0xa000);
|
|
|
|
RD_FB_CMD_REG(ha, reg); /* PCI Posting. */
|
|
|
|
} else {
|
|
|
|
WRT_FB_CMD_REG(ha, reg, 0x00fc);
|
|
|
|
|
|
|
|
/* Read back fb_cmd until zero or 3 seconds max */
|
|
|
|
for (cnt = 0; cnt < 3000; cnt++) {
|
|
|
|
if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0)
|
|
|
|
break;
|
|
|
|
udelay(100);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Select RISC module registers. */
|
|
|
|
WRT_REG_WORD(®->ctrl_status, 0);
|
|
|
|
RD_REG_WORD(®->ctrl_status); /* PCI Posting. */
|
|
|
|
|
|
|
|
/* Reset RISC processor. */
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RESET_RISC);
|
|
|
|
RD_REG_WORD(®->hccr); /* PCI Posting. */
|
|
|
|
|
|
|
|
/* Release RISC processor. */
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC);
|
|
|
|
RD_REG_WORD(®->hccr); /* PCI Posting. */
|
|
|
|
}
|
|
|
|
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT);
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_CLR_HOST_INT);
|
|
|
|
|
|
|
|
/* Reset ISP chip. */
|
|
|
|
WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET);
|
|
|
|
|
|
|
|
/* Wait for RISC to recover from reset. */
|
|
|
|
if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
|
|
|
|
/*
|
|
|
|
* It is necessary to for a delay here since the card doesn't
|
|
|
|
* respond to PCI reads during a reset. On some architectures
|
|
|
|
* this will result in an MCA.
|
|
|
|
*/
|
|
|
|
udelay(20);
|
|
|
|
for (cnt = 30000; cnt; cnt--) {
|
|
|
|
if ((RD_REG_WORD(®->ctrl_status) &
|
|
|
|
CSR_ISP_SOFT_RESET) == 0)
|
|
|
|
break;
|
|
|
|
udelay(100);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
udelay(10);
|
|
|
|
|
|
|
|
/* Reset RISC processor. */
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RESET_RISC);
|
|
|
|
|
|
|
|
WRT_REG_WORD(®->semaphore, 0);
|
|
|
|
|
|
|
|
/* Release RISC processor. */
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC);
|
|
|
|
RD_REG_WORD(®->hccr); /* PCI Posting. */
|
|
|
|
|
|
|
|
if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
|
|
|
|
for (cnt = 0; cnt < 30000; cnt++) {
|
2006-05-17 16:09:06 -06:00
|
|
|
if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY)
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
udelay(100);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
udelay(100);
|
|
|
|
|
|
|
|
/* Turn on master enable */
|
|
|
|
cmd |= PCI_COMMAND_MASTER;
|
|
|
|
pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
|
|
|
|
|
|
|
|
/* Disable RISC pause on FPM parity error. */
|
|
|
|
if (!IS_QLA2100(ha)) {
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_DISABLE_PARITY_PAUSE);
|
|
|
|
RD_REG_WORD(®->hccr); /* PCI Posting. */
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
}
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
/**
|
2005-07-08 18:59:26 -06:00
|
|
|
* qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
|
2005-07-06 11:31:37 -06:00
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
2005-07-08 18:59:26 -06:00
|
|
|
static inline void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_reset_risc(scsi_qla_host_t *vha)
|
2005-07-06 11:31:37 -06:00
|
|
|
{
|
|
|
|
unsigned long flags = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:31:37 -06:00
|
|
|
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
|
|
|
uint32_t cnt, d2;
|
2005-11-08 15:37:48 -07:00
|
|
|
uint16_t wd;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
/* Reset RISC. */
|
|
|
|
WRT_REG_DWORD(®->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
|
|
|
|
for (cnt = 0; cnt < 30000; cnt++) {
|
|
|
|
if ((RD_REG_DWORD(®->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
udelay(10);
|
|
|
|
}
|
|
|
|
|
|
|
|
WRT_REG_DWORD(®->ctrl_status,
|
|
|
|
CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
|
2005-11-08 15:37:48 -07:00
|
|
|
pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
|
2005-07-08 18:59:26 -06:00
|
|
|
|
2005-11-08 15:37:48 -07:00
|
|
|
udelay(100);
|
2005-07-08 18:59:26 -06:00
|
|
|
/* Wait for firmware to complete NVRAM accesses. */
|
|
|
|
d2 = (uint32_t) RD_REG_WORD(®->mailbox0);
|
|
|
|
for (cnt = 10000 ; cnt && d2; cnt--) {
|
|
|
|
udelay(5);
|
|
|
|
d2 = (uint32_t) RD_REG_WORD(®->mailbox0);
|
|
|
|
barrier();
|
|
|
|
}
|
|
|
|
|
2005-11-08 15:37:48 -07:00
|
|
|
/* Wait for soft-reset to complete. */
|
2005-07-06 11:31:37 -06:00
|
|
|
d2 = RD_REG_DWORD(®->ctrl_status);
|
|
|
|
for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) {
|
|
|
|
udelay(5);
|
|
|
|
d2 = RD_REG_DWORD(®->ctrl_status);
|
|
|
|
barrier();
|
|
|
|
}
|
|
|
|
|
|
|
|
WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET);
|
|
|
|
RD_REG_DWORD(®->hccr);
|
|
|
|
|
|
|
|
WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE);
|
|
|
|
RD_REG_DWORD(®->hccr);
|
|
|
|
|
|
|
|
WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET);
|
|
|
|
RD_REG_DWORD(®->hccr);
|
|
|
|
|
|
|
|
d2 = (uint32_t) RD_REG_WORD(®->mailbox0);
|
|
|
|
for (cnt = 6000000 ; cnt && d2; cnt--) {
|
|
|
|
udelay(5);
|
|
|
|
d2 = (uint32_t) RD_REG_WORD(®->mailbox0);
|
|
|
|
barrier();
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
2009-01-05 12:18:06 -07:00
|
|
|
|
|
|
|
if (IS_NOPOLLING_TYPE(ha))
|
|
|
|
ha->isp_ops->enable_intrs(ha);
|
2005-07-06 11:31:37 -06:00
|
|
|
}
|
|
|
|
|
2005-07-08 18:59:26 -06:00
|
|
|
/**
|
|
|
|
* qla24xx_reset_chip() - Reset ISP24xx chip.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_reset_chip(scsi_qla_host_t *vha)
|
2005-07-08 18:59:26 -06:00
|
|
|
{
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2009-12-15 22:29:46 -07:00
|
|
|
|
|
|
|
if (pci_channel_offline(ha->pdev) &&
|
|
|
|
ha->flags.pci_channel_io_perm_failure) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-07-19 16:06:00 -06:00
|
|
|
ha->isp_ops->disable_intrs(ha);
|
2005-07-08 18:59:26 -06:00
|
|
|
|
|
|
|
/* Perform RISC reset. */
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_reset_risc(vha);
|
2005-07-08 18:59:26 -06:00
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/**
|
|
|
|
* qla2x00_chip_diag() - Test chip for proper operation.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
2005-07-06 11:30:05 -06:00
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_chip_diag(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:30:26 -06:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2005-04-16 16:20:36 -06:00
|
|
|
unsigned long flags = 0;
|
|
|
|
uint16_t data;
|
|
|
|
uint32_t cnt;
|
|
|
|
uint16_t mb[5];
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Assume a failed state */
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
|
|
|
|
|
|
|
DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, (u_long)®->flash_address));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
/* Reset ISP chip. */
|
|
|
|
WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to have a delay here since the card will not respond while
|
|
|
|
* in reset causing an MCA on some architectures.
|
|
|
|
*/
|
|
|
|
udelay(20);
|
|
|
|
data = qla2x00_debounce_register(®->ctrl_status);
|
|
|
|
for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) {
|
|
|
|
udelay(5);
|
|
|
|
data = RD_REG_WORD(®->ctrl_status);
|
|
|
|
barrier();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!cnt)
|
|
|
|
goto chip_diag_failed;
|
|
|
|
|
|
|
|
DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
|
2009-04-06 23:33:39 -06:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Reset RISC processor. */
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RESET_RISC);
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC);
|
|
|
|
|
|
|
|
/* Workaround for QLA2312 PCI parity error */
|
|
|
|
if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
|
|
|
|
data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0));
|
|
|
|
for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) {
|
|
|
|
udelay(5);
|
|
|
|
data = RD_MAILBOX_REG(ha, reg, 0);
|
2005-07-06 11:32:07 -06:00
|
|
|
barrier();
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
} else
|
|
|
|
udelay(10);
|
|
|
|
|
|
|
|
if (!cnt)
|
|
|
|
goto chip_diag_failed;
|
|
|
|
|
|
|
|
/* Check product ID of chip */
|
2009-04-06 23:33:39 -06:00
|
|
|
DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
mb[1] = RD_MAILBOX_REG(ha, reg, 1);
|
|
|
|
mb[2] = RD_MAILBOX_REG(ha, reg, 2);
|
|
|
|
mb[3] = RD_MAILBOX_REG(ha, reg, 3);
|
|
|
|
mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
|
|
|
|
if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
|
|
|
|
mb[3] != PROD_ID_3) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);
|
|
|
|
|
|
|
|
goto chip_diag_failed;
|
|
|
|
}
|
|
|
|
ha->product_id[0] = mb[1];
|
|
|
|
ha->product_id[1] = mb[2];
|
|
|
|
ha->product_id[2] = mb[3];
|
|
|
|
ha->product_id[3] = mb[4];
|
|
|
|
|
|
|
|
/* Adjust fw RISC transfer size */
|
2008-12-09 17:45:39 -07:00
|
|
|
if (req->length > 1024)
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
|
|
|
|
else
|
|
|
|
ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
|
2008-12-09 17:45:39 -07:00
|
|
|
req->length;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (IS_QLA2200(ha) &&
|
|
|
|
RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
|
|
|
|
/* Limit firmware transfer size with a 2200A */
|
|
|
|
DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2006-03-09 15:27:08 -07:00
|
|
|
ha->device_type |= DT_ISP2200A;
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->fw_transfer_size = 128;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Wrap Incoming Mailboxes Test. */
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", vha->host_no));
|
|
|
|
rval = qla2x00_mbx_reg_test(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval) {
|
|
|
|
DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Failed mailbox send register test\n");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Flag a successful rval */
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
}
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
chip_diag_failed:
|
|
|
|
if (rval)
|
|
|
|
DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
|
2008-11-06 11:40:51 -07:00
|
|
|
"****\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
/**
|
|
|
|
* qla24xx_chip_diag() - Test ISP24xx for proper operation.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_chip_diag(scsi_qla_host_t *vha)
|
2005-07-06 11:31:37 -06:00
|
|
|
{
|
|
|
|
int rval;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2010-04-12 18:59:55 -06:00
|
|
|
if (IS_QLA82XX(ha))
|
|
|
|
return QLA_SUCCESS;
|
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_mbx_reg_test(vha);
|
2005-07-06 11:31:37 -06:00
|
|
|
if (rval) {
|
|
|
|
DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-07-06 11:31:37 -06:00
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Failed mailbox send register test\n");
|
|
|
|
} else {
|
|
|
|
/* Flag a successful rval */
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2006-06-23 17:10:29 -06:00
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
|
2005-07-06 11:31:37 -06:00
|
|
|
{
|
2006-06-23 17:10:29 -06:00
|
|
|
int rval;
|
|
|
|
uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size,
|
2008-12-09 17:45:39 -07:00
|
|
|
eft_size, fce_size, mq_size;
|
2008-01-17 10:02:17 -07:00
|
|
|
dma_addr_t tc_dma;
|
|
|
|
void *tc;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
|
|
|
struct rsp_que *rsp = ha->rsp_q_map[0];
|
2006-06-23 17:10:29 -06:00
|
|
|
|
|
|
|
if (ha->fw_dump) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Firmware dump previously allocated.\n");
|
|
|
|
return;
|
|
|
|
}
|
2006-05-17 16:09:50 -06:00
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
ha->fw_dumped = 0;
|
2008-12-09 17:45:39 -07:00
|
|
|
fixed_size = mem_size = eft_size = fce_size = mq_size = 0;
|
2006-05-17 16:09:50 -06:00
|
|
|
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
|
2006-06-23 17:10:29 -06:00
|
|
|
fixed_size = sizeof(struct qla2100_fw_dump);
|
2006-05-17 16:09:50 -06:00
|
|
|
} else if (IS_QLA23XX(ha)) {
|
2006-06-23 17:10:29 -06:00
|
|
|
fixed_size = offsetof(struct qla2300_fw_dump, data_ram);
|
|
|
|
mem_size = (ha->fw_memory_size - 0x11000 + 1) *
|
|
|
|
sizeof(uint16_t);
|
2007-07-19 16:05:56 -06:00
|
|
|
} else if (IS_FWI2_CAPABLE(ha)) {
|
2009-01-05 12:18:11 -07:00
|
|
|
if (IS_QLA81XX(ha))
|
|
|
|
fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem);
|
|
|
|
else if (IS_QLA25XX(ha))
|
|
|
|
fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem);
|
|
|
|
else
|
|
|
|
fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem);
|
2006-06-23 17:10:29 -06:00
|
|
|
mem_size = (ha->fw_memory_size - 0x100000 + 1) *
|
|
|
|
sizeof(uint32_t);
|
2008-12-09 17:45:39 -07:00
|
|
|
if (ha->mqenable)
|
|
|
|
mq_size = sizeof(struct qla2xxx_mq_chain);
|
2008-01-17 10:02:17 -07:00
|
|
|
/* Allocate memory for Fibre Channel Event Buffer. */
|
2009-01-05 12:18:11 -07:00
|
|
|
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
|
2008-07-10 17:55:54 -06:00
|
|
|
goto try_eft;
|
2008-01-17 10:02:17 -07:00
|
|
|
|
|
|
|
tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma,
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!tc) {
|
|
|
|
qla_printk(KERN_WARNING, ha, "Unable to allocate "
|
|
|
|
"(%d KB) for FCE.\n", FCE_SIZE / 1024);
|
2008-12-18 11:06:15 -07:00
|
|
|
goto try_eft;
|
2008-01-17 10:02:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(tc, 0, FCE_SIZE);
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS,
|
2008-01-17 10:02:17 -07:00
|
|
|
ha->fce_mb, &ha->fce_bufs);
|
|
|
|
if (rval) {
|
|
|
|
qla_printk(KERN_WARNING, ha, "Unable to initialize "
|
|
|
|
"FCE (%d).\n", rval);
|
|
|
|
dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc,
|
|
|
|
tc_dma);
|
|
|
|
ha->flags.fce_enabled = 0;
|
2008-12-18 11:06:15 -07:00
|
|
|
goto try_eft;
|
2008-01-17 10:02:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
qla_printk(KERN_INFO, ha, "Allocated (%d KB) for FCE...\n",
|
|
|
|
FCE_SIZE / 1024);
|
|
|
|
|
2009-03-24 10:07:58 -06:00
|
|
|
fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE;
|
2008-01-17 10:02:17 -07:00
|
|
|
ha->flags.fce_enabled = 1;
|
|
|
|
ha->fce_dma = tc_dma;
|
|
|
|
ha->fce = tc;
|
2008-07-10 17:55:54 -06:00
|
|
|
try_eft:
|
|
|
|
/* Allocate memory for Extended Trace Buffer. */
|
|
|
|
tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma,
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!tc) {
|
|
|
|
qla_printk(KERN_WARNING, ha, "Unable to allocate "
|
|
|
|
"(%d KB) for EFT.\n", EFT_SIZE / 1024);
|
|
|
|
goto cont_alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(tc, 0, EFT_SIZE);
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS);
|
2008-07-10 17:55:54 -06:00
|
|
|
if (rval) {
|
|
|
|
qla_printk(KERN_WARNING, ha, "Unable to initialize "
|
|
|
|
"EFT (%d).\n", rval);
|
|
|
|
dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc,
|
|
|
|
tc_dma);
|
|
|
|
goto cont_alloc;
|
|
|
|
}
|
|
|
|
|
|
|
|
qla_printk(KERN_INFO, ha, "Allocated (%d KB) for EFT...\n",
|
|
|
|
EFT_SIZE / 1024);
|
|
|
|
|
|
|
|
eft_size = EFT_SIZE;
|
|
|
|
ha->eft_dma = tc_dma;
|
|
|
|
ha->eft = tc;
|
2006-05-17 16:09:50 -06:00
|
|
|
}
|
2006-06-23 17:10:29 -06:00
|
|
|
cont_alloc:
|
2008-12-09 17:45:39 -07:00
|
|
|
req_q_size = req->length * sizeof(request_t);
|
|
|
|
rsp_q_size = rsp->length * sizeof(response_t);
|
2006-06-23 17:10:29 -06:00
|
|
|
|
|
|
|
dump_size = offsetof(struct qla2xxx_fw_dump, isp);
|
2009-04-06 23:33:40 -06:00
|
|
|
dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size;
|
2009-01-05 12:18:08 -07:00
|
|
|
ha->chain_offset = dump_size;
|
|
|
|
dump_size += mq_size + fce_size;
|
2006-05-17 16:09:50 -06:00
|
|
|
|
|
|
|
ha->fw_dump = vmalloc(dump_size);
|
2006-06-23 17:10:29 -06:00
|
|
|
if (!ha->fw_dump) {
|
2005-07-06 11:31:37 -06:00
|
|
|
qla_printk(KERN_WARNING, ha, "Unable to allocate (%d KB) for "
|
2006-05-17 16:09:50 -06:00
|
|
|
"firmware dump!!!\n", dump_size / 1024);
|
2006-06-23 17:10:29 -06:00
|
|
|
|
|
|
|
if (ha->eft) {
|
|
|
|
dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft,
|
|
|
|
ha->eft_dma);
|
|
|
|
ha->eft = NULL;
|
|
|
|
ha->eft_dma = 0;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
qla_printk(KERN_INFO, ha, "Allocated (%d KB) for firmware dump...\n",
|
|
|
|
dump_size / 1024);
|
|
|
|
|
|
|
|
ha->fw_dump_len = dump_size;
|
|
|
|
ha->fw_dump->signature[0] = 'Q';
|
|
|
|
ha->fw_dump->signature[1] = 'L';
|
|
|
|
ha->fw_dump->signature[2] = 'G';
|
|
|
|
ha->fw_dump->signature[3] = 'C';
|
|
|
|
ha->fw_dump->version = __constant_htonl(1);
|
|
|
|
|
|
|
|
ha->fw_dump->fixed_size = htonl(fixed_size);
|
|
|
|
ha->fw_dump->mem_size = htonl(mem_size);
|
|
|
|
ha->fw_dump->req_q_size = htonl(req_q_size);
|
|
|
|
ha->fw_dump->rsp_q_size = htonl(rsp_q_size);
|
|
|
|
|
|
|
|
ha->fw_dump->eft_size = htonl(eft_size);
|
|
|
|
ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma));
|
|
|
|
ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma));
|
|
|
|
|
|
|
|
ha->fw_dump->header_size =
|
|
|
|
htonl(offsetof(struct qla2xxx_fw_dump, isp));
|
2005-07-06 11:31:37 -06:00
|
|
|
}
|
|
|
|
|
2009-06-03 10:55:30 -06:00
|
|
|
static int
|
|
|
|
qla81xx_mpi_sync(scsi_qla_host_t *vha)
|
|
|
|
{
|
|
|
|
#define MPS_MASK 0xe0
|
|
|
|
int rval;
|
|
|
|
uint16_t dc;
|
|
|
|
uint32_t dw;
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
|
|
|
|
if (!IS_QLA81XX(vha->hw))
|
|
|
|
return QLA_SUCCESS;
|
|
|
|
|
|
|
|
rval = qla2x00_write_ram_word(vha, 0x7c00, 1);
|
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
DEBUG2(qla_printk(KERN_WARNING, ha,
|
|
|
|
"Sync-MPI: Unable to acquire semaphore.\n"));
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
pci_read_config_word(vha->hw->pdev, 0x54, &dc);
|
|
|
|
rval = qla2x00_read_ram_word(vha, 0x7a15, &dw);
|
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
DEBUG2(qla_printk(KERN_WARNING, ha,
|
|
|
|
"Sync-MPI: Unable to read sync.\n"));
|
|
|
|
goto done_release;
|
|
|
|
}
|
|
|
|
|
|
|
|
dc &= MPS_MASK;
|
|
|
|
if (dc == (dw & MPS_MASK))
|
|
|
|
goto done_release;
|
|
|
|
|
|
|
|
dw &= ~MPS_MASK;
|
|
|
|
dw |= dc;
|
|
|
|
rval = qla2x00_write_ram_word(vha, 0x7a15, dw);
|
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
DEBUG2(qla_printk(KERN_WARNING, ha,
|
|
|
|
"Sync-MPI: Unable to gain sync.\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
done_release:
|
|
|
|
rval = qla2x00_write_ram_word(vha, 0x7c00, 0);
|
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
DEBUG2(qla_printk(KERN_WARNING, ha,
|
|
|
|
"Sync-MPI: Unable to release semaphore.\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/**
|
|
|
|
* qla2x00_setup_chip() - Load and start RISC firmware.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_setup_chip(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2005-07-06 11:31:37 -06:00
|
|
|
int rval;
|
|
|
|
uint32_t srisc_address = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-01-31 13:33:49 -07:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
|
|
|
unsigned long flags;
|
2009-03-24 10:08:00 -06:00
|
|
|
uint16_t fw_major_version;
|
2008-01-31 13:33:49 -07:00
|
|
|
|
2010-04-12 18:59:55 -06:00
|
|
|
if (IS_QLA82XX(ha)) {
|
|
|
|
rval = ha->isp_ops->load_risc(vha, &srisc_address);
|
|
|
|
if (rval == QLA_SUCCESS)
|
|
|
|
goto enable_82xx_npiv;
|
2010-05-28 16:08:15 -06:00
|
|
|
else
|
|
|
|
goto failed;
|
2010-04-12 18:59:55 -06:00
|
|
|
}
|
|
|
|
|
2008-01-31 13:33:49 -07:00
|
|
|
if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
|
|
|
|
/* Disable SRAM, Instruction RAM and GP RAM parity. */
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x0));
|
|
|
|
RD_REG_WORD(®->hccr);
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-06-03 10:55:30 -06:00
|
|
|
qla81xx_mpi_sync(vha);
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Load firmware sequences */
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = ha->isp_ops->load_risc(vha, &srisc_address);
|
2005-07-06 11:31:37 -06:00
|
|
|
if (rval == QLA_SUCCESS) {
|
2005-04-16 16:20:36 -06:00
|
|
|
DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
|
2008-11-06 11:40:51 -07:00
|
|
|
"code.\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_verify_checksum(vha, srisc_address);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval == QLA_SUCCESS) {
|
|
|
|
/* Start firmware execution. */
|
|
|
|
DEBUG(printk("scsi(%ld): Checksum OK, start "
|
2008-11-06 11:40:51 -07:00
|
|
|
"firmware.\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_execute_fw(vha, srisc_address);
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Retrieve firmware information. */
|
2009-03-24 10:08:00 -06:00
|
|
|
if (rval == QLA_SUCCESS) {
|
2010-04-12 18:59:55 -06:00
|
|
|
enable_82xx_npiv:
|
2009-03-24 10:08:00 -06:00
|
|
|
fw_major_version = ha->fw_major_version;
|
2009-06-03 10:55:20 -06:00
|
|
|
rval = qla2x00_get_fw_version(vha,
|
2005-04-16 16:20:36 -06:00
|
|
|
&ha->fw_major_version,
|
|
|
|
&ha->fw_minor_version,
|
|
|
|
&ha->fw_subminor_version,
|
2009-01-05 12:18:11 -07:00
|
|
|
&ha->fw_attributes, &ha->fw_memory_size,
|
2009-03-24 10:08:03 -06:00
|
|
|
ha->mpi_version, &ha->mpi_capabilities,
|
|
|
|
ha->phy_version);
|
2009-06-03 10:55:20 -06:00
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
goto failed;
|
2007-07-05 14:16:51 -06:00
|
|
|
ha->flags.npiv_supported = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
if (IS_QLA2XXX_MIDTYPE(ha) &&
|
2008-08-13 22:36:59 -06:00
|
|
|
(ha->fw_attributes & BIT_2)) {
|
2007-07-05 14:16:51 -06:00
|
|
|
ha->flags.npiv_supported = 1;
|
2007-09-20 15:07:43 -06:00
|
|
|
if ((!ha->max_npiv_vports) ||
|
|
|
|
((ha->max_npiv_vports + 1) %
|
2007-11-12 11:30:58 -07:00
|
|
|
MIN_MULTI_ID_FABRIC))
|
2007-09-20 15:07:43 -06:00
|
|
|
ha->max_npiv_vports =
|
2007-11-12 11:30:58 -07:00
|
|
|
MIN_MULTI_ID_FABRIC - 1;
|
2007-09-20 15:07:43 -06:00
|
|
|
}
|
2009-03-24 10:08:16 -06:00
|
|
|
qla2x00_get_resource_cnts(vha, NULL,
|
|
|
|
&ha->fw_xcb_count, NULL, NULL,
|
2009-10-13 16:16:49 -06:00
|
|
|
&ha->max_npiv_vports, NULL);
|
2009-03-24 10:08:15 -06:00
|
|
|
|
2010-04-12 18:59:55 -06:00
|
|
|
if (!fw_major_version && ql2xallocfwdump) {
|
|
|
|
if (!IS_QLA82XX(ha))
|
|
|
|
qla2x00_alloc_fw_dump(vha);
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
DEBUG2(printk(KERN_INFO
|
|
|
|
"scsi(%ld): ISP Firmware failed checksum.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-31 13:33:49 -07:00
|
|
|
if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) {
|
|
|
|
/* Enable proper parity. */
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
if (IS_QLA2300(ha))
|
|
|
|
/* SRAM parity */
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_ENABLE_PARITY + 0x1);
|
|
|
|
else
|
|
|
|
/* SRAM, Instruction RAM and GP RAM parity */
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_ENABLE_PARITY + 0x7);
|
|
|
|
RD_REG_WORD(®->hccr);
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
}
|
|
|
|
|
2009-03-24 10:08:06 -06:00
|
|
|
if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) {
|
|
|
|
uint32_t size;
|
|
|
|
|
|
|
|
rval = qla81xx_fac_get_sector_size(vha, &size);
|
|
|
|
if (rval == QLA_SUCCESS) {
|
|
|
|
ha->flags.fac_supported = 1;
|
|
|
|
ha->fdt_block_size = size << 2;
|
|
|
|
} else {
|
|
|
|
qla_printk(KERN_ERR, ha,
|
|
|
|
"Unsupported FAC firmware (%d.%02d.%02d).\n",
|
|
|
|
ha->fw_major_version, ha->fw_minor_version,
|
|
|
|
ha->fw_subminor_version);
|
|
|
|
}
|
|
|
|
}
|
2009-06-03 10:55:20 -06:00
|
|
|
failed:
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval) {
|
|
|
|
DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qla2x00_init_response_q_entries() - Initializes response queue entries.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Beginning of request ring has initialization control block already built
|
|
|
|
* by nvram config routine.
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
2008-12-09 17:45:39 -07:00
|
|
|
void
|
|
|
|
qla2x00_init_response_q_entries(struct rsp_que *rsp)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
uint16_t cnt;
|
|
|
|
response_t *pkt;
|
|
|
|
|
2009-04-06 23:33:40 -06:00
|
|
|
rsp->ring_ptr = rsp->ring;
|
|
|
|
rsp->ring_index = 0;
|
|
|
|
rsp->status_srb = NULL;
|
2008-11-06 11:40:51 -07:00
|
|
|
pkt = rsp->ring_ptr;
|
|
|
|
for (cnt = 0; cnt < rsp->length; cnt++) {
|
2005-04-16 16:20:36 -06:00
|
|
|
pkt->signature = RESPONSE_PROCESSED;
|
|
|
|
pkt++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qla2x00_update_fw_options() - Read and process firmware options.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
2005-07-06 11:30:05 -06:00
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_update_fw_options(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
uint16_t swing, emphasis, tx_sens, rx_sens;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
memset(ha->fw_options, 0, sizeof(ha->fw_options));
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_get_fw_options(vha, ha->fw_options);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (IS_QLA2100(ha) || IS_QLA2200(ha))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Serial Link options. */
|
|
|
|
DEBUG3(printk("scsi(%ld): Serial link options:\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
DEBUG3(qla2x00_dump_buffer((uint8_t *)&ha->fw_seriallink_options,
|
|
|
|
sizeof(ha->fw_seriallink_options)));
|
|
|
|
|
|
|
|
ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
|
|
|
|
if (ha->fw_seriallink_options[3] & BIT_2) {
|
|
|
|
ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING;
|
|
|
|
|
|
|
|
/* 1G settings */
|
|
|
|
swing = ha->fw_seriallink_options[2] & (BIT_2 | BIT_1 | BIT_0);
|
|
|
|
emphasis = (ha->fw_seriallink_options[2] &
|
|
|
|
(BIT_4 | BIT_3)) >> 3;
|
|
|
|
tx_sens = ha->fw_seriallink_options[0] &
|
2005-07-06 11:32:07 -06:00
|
|
|
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
|
2005-04-16 16:20:36 -06:00
|
|
|
rx_sens = (ha->fw_seriallink_options[0] &
|
|
|
|
(BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
|
|
|
|
ha->fw_options[10] = (emphasis << 14) | (swing << 8);
|
|
|
|
if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
|
|
|
|
if (rx_sens == 0x0)
|
|
|
|
rx_sens = 0x3;
|
|
|
|
ha->fw_options[10] |= (tx_sens << 4) | rx_sens;
|
|
|
|
} else if (IS_QLA2322(ha) || IS_QLA6322(ha))
|
|
|
|
ha->fw_options[10] |= BIT_5 |
|
|
|
|
((rx_sens & (BIT_1 | BIT_0)) << 2) |
|
|
|
|
(tx_sens & (BIT_1 | BIT_0));
|
|
|
|
|
|
|
|
/* 2G settings */
|
|
|
|
swing = (ha->fw_seriallink_options[2] &
|
|
|
|
(BIT_7 | BIT_6 | BIT_5)) >> 5;
|
|
|
|
emphasis = ha->fw_seriallink_options[3] & (BIT_1 | BIT_0);
|
|
|
|
tx_sens = ha->fw_seriallink_options[1] &
|
2005-07-06 11:32:07 -06:00
|
|
|
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
|
2005-04-16 16:20:36 -06:00
|
|
|
rx_sens = (ha->fw_seriallink_options[1] &
|
|
|
|
(BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
|
|
|
|
ha->fw_options[11] = (emphasis << 14) | (swing << 8);
|
|
|
|
if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
|
|
|
|
if (rx_sens == 0x0)
|
|
|
|
rx_sens = 0x3;
|
|
|
|
ha->fw_options[11] |= (tx_sens << 4) | rx_sens;
|
|
|
|
} else if (IS_QLA2322(ha) || IS_QLA6322(ha))
|
|
|
|
ha->fw_options[11] |= BIT_5 |
|
|
|
|
((rx_sens & (BIT_1 | BIT_0)) << 2) |
|
|
|
|
(tx_sens & (BIT_1 | BIT_0));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FCP2 options. */
|
|
|
|
/* Return command IOCBs without waiting for an ABTS to complete. */
|
|
|
|
ha->fw_options[3] |= BIT_13;
|
|
|
|
|
|
|
|
/* LED scheme. */
|
|
|
|
if (ha->flags.enable_led_scheme)
|
|
|
|
ha->fw_options[2] |= BIT_12;
|
|
|
|
|
2006-03-09 15:27:18 -07:00
|
|
|
/* Detect ISP6312. */
|
|
|
|
if (IS_QLA6312(ha))
|
|
|
|
ha->fw_options[2] |= BIT_13;
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Update firmware options. */
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_set_fw_options(vha, ha->fw_options);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_update_fw_options(scsi_qla_host_t *vha)
|
2005-07-06 11:31:37 -06:00
|
|
|
{
|
|
|
|
int rval;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2010-04-12 18:59:55 -06:00
|
|
|
if (IS_QLA82XX(ha))
|
|
|
|
return;
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
/* Update Serial Link options. */
|
2006-01-13 18:05:32 -07:00
|
|
|
if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0)
|
2005-07-06 11:31:37 -06:00
|
|
|
return;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_set_serdes_params(vha,
|
2006-01-13 18:05:32 -07:00
|
|
|
le16_to_cpu(ha->fw_seriallink_options24[1]),
|
|
|
|
le16_to_cpu(ha->fw_seriallink_options24[2]),
|
|
|
|
le16_to_cpu(ha->fw_seriallink_options24[3]));
|
2005-07-06 11:31:37 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to update Serial Link options (%x).\n", rval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-06 11:30:05 -06:00
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_config_rings(struct scsi_qla_host *vha)
|
2005-07-06 11:30:05 -06:00
|
|
|
{
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:30:26 -06:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
|
|
|
struct rsp_que *rsp = ha->rsp_q_map[0];
|
2005-07-06 11:30:05 -06:00
|
|
|
|
|
|
|
/* Setup ring parameters in initialization control block. */
|
|
|
|
ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0);
|
|
|
|
ha->init_cb->response_q_inpointer = __constant_cpu_to_le16(0);
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->init_cb->request_q_length = cpu_to_le16(req->length);
|
|
|
|
ha->init_cb->response_q_length = cpu_to_le16(rsp->length);
|
|
|
|
ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
|
|
|
|
ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
|
|
|
|
ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
|
|
|
|
ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
|
2005-07-06 11:30:05 -06:00
|
|
|
|
|
|
|
WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0);
|
|
|
|
WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0);
|
|
|
|
WRT_REG_WORD(ISP_RSP_Q_IN(ha, reg), 0);
|
|
|
|
WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), 0);
|
|
|
|
RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */
|
|
|
|
}
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_config_rings(struct scsi_qla_host *vha)
|
2005-07-06 11:31:37 -06:00
|
|
|
{
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-12-09 17:45:39 -07:00
|
|
|
device_reg_t __iomem *reg = ISP_QUE_REG(ha, 0);
|
|
|
|
struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp;
|
|
|
|
struct qla_msix_entry *msix;
|
2005-07-06 11:31:37 -06:00
|
|
|
struct init_cb_24xx *icb;
|
2008-12-09 17:45:39 -07:00
|
|
|
uint16_t rid = 0;
|
|
|
|
struct req_que *req = ha->req_q_map[0];
|
|
|
|
struct rsp_que *rsp = ha->rsp_q_map[0];
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
/* Setup ring parameters in initialization control block. */
|
2005-07-06 11:31:37 -06:00
|
|
|
icb = (struct init_cb_24xx *)ha->init_cb;
|
|
|
|
icb->request_q_outpointer = __constant_cpu_to_le16(0);
|
|
|
|
icb->response_q_inpointer = __constant_cpu_to_le16(0);
|
2008-11-06 11:40:51 -07:00
|
|
|
icb->request_q_length = cpu_to_le16(req->length);
|
|
|
|
icb->response_q_length = cpu_to_le16(rsp->length);
|
|
|
|
icb->request_q_address[0] = cpu_to_le32(LSD(req->dma));
|
|
|
|
icb->request_q_address[1] = cpu_to_le32(MSD(req->dma));
|
|
|
|
icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma));
|
|
|
|
icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma));
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
if (ha->mqenable) {
|
|
|
|
icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS);
|
|
|
|
icb->rid = __constant_cpu_to_le16(rid);
|
|
|
|
if (ha->flags.msix_enabled) {
|
|
|
|
msix = &ha->msix_entries[1];
|
|
|
|
DEBUG2_17(printk(KERN_INFO
|
2009-04-06 23:33:40 -06:00
|
|
|
"Registering vector 0x%x for base que\n", msix->entry));
|
2008-12-09 17:45:39 -07:00
|
|
|
icb->msix = cpu_to_le16(msix->entry);
|
|
|
|
}
|
|
|
|
/* Use alternate PCI bus number */
|
|
|
|
if (MSB(rid))
|
|
|
|
icb->firmware_options_2 |=
|
|
|
|
__constant_cpu_to_le32(BIT_19);
|
|
|
|
/* Use alternate PCI devfn */
|
|
|
|
if (LSB(rid))
|
|
|
|
icb->firmware_options_2 |=
|
|
|
|
__constant_cpu_to_le32(BIT_18);
|
|
|
|
|
2009-12-02 11:36:55 -07:00
|
|
|
/* Use Disable MSIX Handshake mode for capable adapters */
|
|
|
|
if (IS_MSIX_NACK_CAPABLE(ha)) {
|
|
|
|
icb->firmware_options_2 &=
|
|
|
|
__constant_cpu_to_le32(~BIT_22);
|
|
|
|
ha->flags.disable_msix_handshake = 1;
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"MSIX Handshake Disable Mode turned on\n");
|
|
|
|
} else {
|
|
|
|
icb->firmware_options_2 |=
|
|
|
|
__constant_cpu_to_le32(BIT_22);
|
|
|
|
}
|
2008-12-09 17:45:39 -07:00
|
|
|
icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23);
|
|
|
|
|
|
|
|
WRT_REG_DWORD(®->isp25mq.req_q_in, 0);
|
|
|
|
WRT_REG_DWORD(®->isp25mq.req_q_out, 0);
|
|
|
|
WRT_REG_DWORD(®->isp25mq.rsp_q_in, 0);
|
|
|
|
WRT_REG_DWORD(®->isp25mq.rsp_q_out, 0);
|
|
|
|
} else {
|
|
|
|
WRT_REG_DWORD(®->isp24.req_q_in, 0);
|
|
|
|
WRT_REG_DWORD(®->isp24.req_q_out, 0);
|
|
|
|
WRT_REG_DWORD(®->isp24.rsp_q_in, 0);
|
|
|
|
WRT_REG_DWORD(®->isp24.rsp_q_out, 0);
|
|
|
|
}
|
|
|
|
/* PCI posting */
|
|
|
|
RD_REG_DWORD(&ioreg->hccr);
|
2005-07-06 11:31:37 -06:00
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/**
|
|
|
|
* qla2x00_init_rings() - Initializes firmware.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Beginning of request ring has initialization control block already built
|
|
|
|
* by nvram config routine.
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_init_rings(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
unsigned long flags = 0;
|
2009-01-08 16:41:08 -07:00
|
|
|
int cnt, que;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2009-01-08 16:41:08 -07:00
|
|
|
struct req_que *req;
|
|
|
|
struct rsp_que *rsp;
|
|
|
|
struct scsi_qla_host *vp;
|
2007-07-05 14:16:51 -06:00
|
|
|
struct mid_init_cb_24xx *mid_init_cb =
|
|
|
|
(struct mid_init_cb_24xx *) ha->init_cb;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
/* Clear outstanding commands array. */
|
2009-04-06 23:33:40 -06:00
|
|
|
for (que = 0; que < ha->max_req_queues; que++) {
|
2009-01-08 16:41:08 -07:00
|
|
|
req = ha->req_q_map[que];
|
|
|
|
if (!req)
|
|
|
|
continue;
|
2009-04-06 23:33:40 -06:00
|
|
|
for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
|
2009-01-08 16:41:08 -07:00
|
|
|
req->outstanding_cmds[cnt] = NULL;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-04-06 23:33:40 -06:00
|
|
|
req->current_outstanding_cmd = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-01-08 16:41:08 -07:00
|
|
|
/* Initialize firmware. */
|
|
|
|
req->ring_ptr = req->ring;
|
|
|
|
req->ring_index = 0;
|
|
|
|
req->cnt = req->length;
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-04-06 23:33:40 -06:00
|
|
|
for (que = 0; que < ha->max_rsp_queues; que++) {
|
2009-01-08 16:41:08 -07:00
|
|
|
rsp = ha->rsp_q_map[que];
|
|
|
|
if (!rsp)
|
|
|
|
continue;
|
|
|
|
/* Initialize response queue entries */
|
|
|
|
qla2x00_init_response_q_entries(rsp);
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-01-08 16:41:08 -07:00
|
|
|
/* Clear RSCN queue. */
|
|
|
|
list_for_each_entry(vp, &ha->vp_list, list) {
|
|
|
|
vp->rscn_in_ptr = 0;
|
|
|
|
vp->rscn_out_ptr = 0;
|
|
|
|
}
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->config_rings(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
|
|
|
|
/* Update any ISP specific firmware options before initialization. */
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->update_fw_options(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
DEBUG(printk("scsi(%ld): Issue init firmware.\n", vha->host_no));
|
2007-07-05 14:16:51 -06:00
|
|
|
|
2009-03-05 12:07:01 -07:00
|
|
|
if (ha->flags.npiv_supported) {
|
|
|
|
if (ha->operating_mode == LOOP)
|
|
|
|
ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1;
|
2008-01-17 10:02:19 -07:00
|
|
|
mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports);
|
2009-03-05 12:07:01 -07:00
|
|
|
}
|
|
|
|
|
2009-03-24 10:08:16 -06:00
|
|
|
if (IS_FWI2_CAPABLE(ha)) {
|
|
|
|
mid_init_cb->options = __constant_cpu_to_le16(BIT_1);
|
|
|
|
mid_init_cb->init_cb.execution_throttle =
|
|
|
|
cpu_to_le16(ha->fw_xcb_count);
|
|
|
|
}
|
2007-07-05 14:16:51 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_init_firmware(vha, ha->init_cb_size);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval) {
|
|
|
|
DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
} else {
|
|
|
|
DEBUG3(printk("scsi(%ld): Init firmware -- success.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* qla2x00_fw_ready() - Waits for firmware ready.
|
|
|
|
* @ha: HA context
|
|
|
|
*
|
|
|
|
* Returns 0 on success.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_fw_ready(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
2008-04-03 14:13:26 -06:00
|
|
|
unsigned long wtime, mtime, cs84xx_time;
|
2005-04-16 16:20:36 -06:00
|
|
|
uint16_t min_wait; /* Minimum wait time if loop is down */
|
|
|
|
uint16_t wait_time; /* Wait time if loop is coming ready */
|
2009-06-03 10:55:29 -06:00
|
|
|
uint16_t state[5];
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
|
|
|
|
/* 20 seconds for loop down. */
|
2005-07-06 11:32:07 -06:00
|
|
|
min_wait = 20;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Firmware should take at most one RATOV to login, plus 5 seconds for
|
|
|
|
* our own processing.
|
|
|
|
*/
|
|
|
|
if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) {
|
|
|
|
wait_time = min_wait;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Min wait time if loop down */
|
|
|
|
mtime = jiffies + (min_wait * HZ);
|
|
|
|
|
|
|
|
/* wait time before firmware ready */
|
|
|
|
wtime = jiffies + (wait_time * HZ);
|
|
|
|
|
|
|
|
/* Wait for ISP to finish LIP */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (!vha->flags.init_done)
|
2005-04-16 16:20:36 -06:00
|
|
|
qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n");
|
|
|
|
|
|
|
|
DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
do {
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_get_firmware_state(vha, state);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval == QLA_SUCCESS) {
|
2008-04-03 14:13:26 -06:00
|
|
|
if (state[0] < FSTATE_LOSS_OF_SYNC) {
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->device_flags &= ~DFLG_NO_CABLE;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2008-04-03 14:13:26 -06:00
|
|
|
if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) {
|
|
|
|
DEBUG16(printk("scsi(%ld): fw_state=%x "
|
2008-11-06 11:40:51 -07:00
|
|
|
"84xx=%x.\n", vha->host_no, state[0],
|
2008-04-03 14:13:26 -06:00
|
|
|
state[2]));
|
|
|
|
if ((state[2] & FSTATE_LOGGED_IN) &&
|
|
|
|
(state[2] & FSTATE_WAITING_FOR_VERIFY)) {
|
|
|
|
DEBUG16(printk("scsi(%ld): Sending "
|
2008-11-06 11:40:51 -07:00
|
|
|
"verify iocb.\n", vha->host_no));
|
2008-04-03 14:13:26 -06:00
|
|
|
|
|
|
|
cs84xx_time = jiffies;
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla84xx_init_chip(vha);
|
2008-04-03 14:13:26 -06:00
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Add time taken to initialize. */
|
|
|
|
cs84xx_time = jiffies - cs84xx_time;
|
|
|
|
wtime += cs84xx_time;
|
|
|
|
mtime += cs84xx_time;
|
|
|
|
DEBUG16(printk("scsi(%ld): Increasing "
|
|
|
|
"wait time by %ld. New time %ld\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, cs84xx_time, wtime));
|
2008-04-03 14:13:26 -06:00
|
|
|
}
|
|
|
|
} else if (state[0] == FSTATE_READY) {
|
2005-04-16 16:20:36 -06:00
|
|
|
DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_get_retry_cnt(vha, &ha->retry_count,
|
2005-04-16 16:20:36 -06:00
|
|
|
&ha->login_timeout, &ha->r_a_tov);
|
|
|
|
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (atomic_read(&vha->loop_down_timer) &&
|
2008-04-03 14:13:26 -06:00
|
|
|
state[0] != FSTATE_READY) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Loop down. Timeout on min_wait for states
|
2005-07-06 11:32:07 -06:00
|
|
|
* other than Wait for Login.
|
|
|
|
*/
|
2005-04-16 16:20:36 -06:00
|
|
|
if (time_after_eq(jiffies, mtime)) {
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"Cable is unplugged...\n");
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->device_flags |= DFLG_NO_CABLE;
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Mailbox cmd failed. Timeout on min_wait. */
|
|
|
|
if (time_after_eq(jiffies, mtime))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (time_after_eq(jiffies, wtime))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Delay for a while */
|
|
|
|
msleep(500);
|
|
|
|
|
|
|
|
DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, state[0], jiffies));
|
2005-04-16 16:20:36 -06:00
|
|
|
} while (1);
|
|
|
|
|
2009-06-03 10:55:29 -06:00
|
|
|
DEBUG(printk("scsi(%ld): fw_state=%x (%x, %x, %x, %x) curr time=%lx.\n",
|
|
|
|
vha->host_no, state[0], state[1], state[2], state[3], state[4],
|
|
|
|
jiffies));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (rval) {
|
|
|
|
DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_configure_hba
|
|
|
|
* Setup adapter context.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter state pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success
|
|
|
|
*
|
|
|
|
* Context:
|
|
|
|
* Kernel context.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_configure_hba(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
uint16_t loop_id;
|
|
|
|
uint16_t topo;
|
2007-07-05 14:16:51 -06:00
|
|
|
uint16_t sw_cap;
|
2005-04-16 16:20:36 -06:00
|
|
|
uint8_t al_pa;
|
|
|
|
uint8_t area;
|
|
|
|
uint8_t domain;
|
|
|
|
char connect_type[22];
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Get host addresses. */
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_get_adapter_id(vha,
|
2007-07-05 14:16:51 -06:00
|
|
|
&loop_id, &al_pa, &area, &domain, &topo, &sw_cap);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
2008-11-06 11:40:51 -07:00
|
|
|
if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) ||
|
2005-11-08 15:37:20 -07:00
|
|
|
(rval == QLA_COMMAND_ERROR && loop_id == 0x7)) {
|
|
|
|
DEBUG2(printk("%s(%ld) Loop is in a transition state\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
__func__, vha->host_no));
|
2005-11-08 15:37:20 -07:00
|
|
|
} else {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"ERROR -- Unable to get host loop ID.\n");
|
2008-11-06 11:40:51 -07:00
|
|
|
set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
2005-11-08 15:37:20 -07:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (topo == 4) {
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"Cannot get topology - retrying.\n");
|
|
|
|
return (QLA_FUNCTION_FAILED);
|
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->loop_id = loop_id;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* initialize */
|
|
|
|
ha->min_external_loopid = SNS_FIRST_LOOP_ID;
|
|
|
|
ha->operating_mode = LOOP;
|
2007-07-05 14:16:51 -06:00
|
|
|
ha->switch_cap = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
switch (topo) {
|
|
|
|
case 0:
|
|
|
|
DEBUG3(printk("scsi(%ld): HBA in NL topology.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->current_topology = ISP_CFG_NL;
|
|
|
|
strcpy(connect_type, "(Loop)");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2007-07-05 14:16:51 -06:00
|
|
|
ha->switch_cap = sw_cap;
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->current_topology = ISP_CFG_FL;
|
|
|
|
strcpy(connect_type, "(FL_Port)");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->operating_mode = P2P;
|
|
|
|
ha->current_topology = ISP_CFG_N;
|
|
|
|
strcpy(connect_type, "(N_Port-to-N_Port)");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2007-07-05 14:16:51 -06:00
|
|
|
ha->switch_cap = sw_cap;
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->operating_mode = P2P;
|
|
|
|
ha->current_topology = ISP_CFG_F;
|
|
|
|
strcpy(connect_type, "(F_Port)");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. "
|
|
|
|
"Using NL.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, topo));
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->current_topology = ISP_CFG_NL;
|
|
|
|
strcpy(connect_type, "(Loop)");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Save Host port and loop ID. */
|
|
|
|
/* byte order - Big Endian */
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->d_id.b.domain = domain;
|
|
|
|
vha->d_id.b.area = area;
|
|
|
|
vha->d_id.b.al_pa = al_pa;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (!vha->flags.init_done)
|
2005-04-16 16:20:36 -06:00
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"Topology - %s, Host Loop address 0x%x\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
connect_type, vha->loop_id);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (rval) {
|
2008-11-06 11:40:51 -07:00
|
|
|
DEBUG2_3(printk("scsi(%ld): FAILED.\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
} else {
|
2008-11-06 11:40:51 -07:00
|
|
|
DEBUG3(printk("scsi(%ld): exiting normally.\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return(rval);
|
|
|
|
}
|
|
|
|
|
2010-04-12 18:59:55 -06:00
|
|
|
inline void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
|
|
|
|
char *def)
|
2007-01-29 11:22:24 -07:00
|
|
|
{
|
|
|
|
char *st, *en;
|
|
|
|
uint16_t index;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2009-08-25 12:36:17 -06:00
|
|
|
int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
|
2010-04-12 18:59:55 -06:00
|
|
|
!IS_QLA8XXX_TYPE(ha);
|
2007-01-29 11:22:24 -07:00
|
|
|
|
|
|
|
if (memcmp(model, BINZERO, len) != 0) {
|
|
|
|
strncpy(ha->model_number, model, len);
|
|
|
|
st = en = ha->model_number;
|
|
|
|
en += len - 1;
|
|
|
|
while (en > st) {
|
|
|
|
if (*en != 0x20 && *en != 0x00)
|
|
|
|
break;
|
|
|
|
*en-- = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
index = (ha->pdev->subsystem_device & 0xff);
|
2009-04-06 23:33:45 -06:00
|
|
|
if (use_tbl &&
|
|
|
|
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
2007-01-29 11:22:24 -07:00
|
|
|
index < QLA_MODEL_NAMES)
|
2008-07-10 17:55:53 -06:00
|
|
|
strncpy(ha->model_desc,
|
|
|
|
qla2x00_model_name[index * 2 + 1],
|
|
|
|
sizeof(ha->model_desc) - 1);
|
2007-01-29 11:22:24 -07:00
|
|
|
} else {
|
|
|
|
index = (ha->pdev->subsystem_device & 0xff);
|
2009-04-06 23:33:45 -06:00
|
|
|
if (use_tbl &&
|
|
|
|
ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
|
2007-01-29 11:22:24 -07:00
|
|
|
index < QLA_MODEL_NAMES) {
|
|
|
|
strcpy(ha->model_number,
|
|
|
|
qla2x00_model_name[index * 2]);
|
2008-07-10 17:55:53 -06:00
|
|
|
strncpy(ha->model_desc,
|
|
|
|
qla2x00_model_name[index * 2 + 1],
|
|
|
|
sizeof(ha->model_desc) - 1);
|
2007-01-29 11:22:24 -07:00
|
|
|
} else {
|
|
|
|
strcpy(ha->model_number, def);
|
|
|
|
}
|
|
|
|
}
|
2008-07-10 17:55:53 -06:00
|
|
|
if (IS_FWI2_CAPABLE(ha))
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2xxx_get_vpd_field(vha, "\x82", ha->model_desc,
|
2008-07-10 17:55:53 -06:00
|
|
|
sizeof(ha->model_desc));
|
2007-01-29 11:22:24 -07:00
|
|
|
}
|
|
|
|
|
2007-04-16 13:37:43 -06:00
|
|
|
/* On sparc systems, obtain port and node WWN from firmware
|
|
|
|
* properties.
|
|
|
|
*/
|
2008-11-06 11:40:51 -07:00
|
|
|
static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *vha, nvram_t *nv)
|
2007-04-16 13:37:43 -06:00
|
|
|
{
|
|
|
|
#ifdef CONFIG_SPARC
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2007-04-16 13:37:43 -06:00
|
|
|
struct pci_dev *pdev = ha->pdev;
|
2007-05-08 01:36:49 -06:00
|
|
|
struct device_node *dp = pci_device_to_OF_node(pdev);
|
|
|
|
const u8 *val;
|
2007-04-16 13:37:43 -06:00
|
|
|
int len;
|
|
|
|
|
|
|
|
val = of_get_property(dp, "port-wwn", &len);
|
|
|
|
if (val && len >= WWN_SIZE)
|
|
|
|
memcpy(nv->port_name, val, WWN_SIZE);
|
|
|
|
|
|
|
|
val = of_get_property(dp, "node-wwn", &len);
|
|
|
|
if (val && len >= WWN_SIZE)
|
|
|
|
memcpy(nv->node_name, val, WWN_SIZE);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/*
|
|
|
|
* NVRAM configuration for ISP 2xxx
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
* initialization control block in response_ring
|
|
|
|
* host adapters parameters in host adapter block
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success.
|
|
|
|
*/
|
2005-07-06 11:30:05 -06:00
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_nvram_config(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2007-04-16 13:37:43 -06:00
|
|
|
int rval;
|
2005-07-06 11:31:37 -06:00
|
|
|
uint8_t chksum = 0;
|
|
|
|
uint16_t cnt;
|
|
|
|
uint8_t *dptr1, *dptr2;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:31:37 -06:00
|
|
|
init_cb_t *icb = ha->init_cb;
|
2007-07-26 14:43:34 -06:00
|
|
|
nvram_t *nv = ha->nvram;
|
|
|
|
uint8_t *ptr = ha->nvram;
|
2005-07-06 11:30:26 -06:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-04-16 13:37:43 -06:00
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Determine NVRAM starting address. */
|
2005-07-06 11:31:37 -06:00
|
|
|
ha->nvram_size = sizeof(nvram_t);
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->nvram_base = 0;
|
|
|
|
if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
|
|
|
|
if ((RD_REG_WORD(®->ctrl_status) >> 14) == 1)
|
|
|
|
ha->nvram_base = 0x80;
|
|
|
|
|
|
|
|
/* Get NVRAM data and calculate checksum. */
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->read_nvram(vha, ptr, ha->nvram_base, ha->nvram_size);
|
2005-07-06 11:31:37 -06:00
|
|
|
for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++)
|
|
|
|
chksum += *ptr++;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
|
2007-07-26 14:43:34 -06:00
|
|
|
DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Bad NVRAM data, set defaults parameters. */
|
|
|
|
if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
|
|
|
|
nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
|
|
|
|
/* Reset NVRAM data. */
|
|
|
|
qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
|
|
|
|
"checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
|
|
|
|
nv->nvram_version);
|
2007-04-16 13:37:43 -06:00
|
|
|
qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
|
|
|
|
"invalid -- WWPN) defaults.\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set default initialization control block.
|
|
|
|
*/
|
|
|
|
memset(nv, 0, ha->nvram_size);
|
|
|
|
nv->parameter_block_version = ICB_VERSION;
|
|
|
|
|
|
|
|
if (IS_QLA23XX(ha)) {
|
|
|
|
nv->firmware_options[0] = BIT_2 | BIT_1;
|
|
|
|
nv->firmware_options[1] = BIT_7 | BIT_5;
|
|
|
|
nv->add_firmware_options[0] = BIT_5;
|
|
|
|
nv->add_firmware_options[1] = BIT_5 | BIT_4;
|
|
|
|
nv->frame_payload_size = __constant_cpu_to_le16(2048);
|
|
|
|
nv->special_options[1] = BIT_7;
|
|
|
|
} else if (IS_QLA2200(ha)) {
|
|
|
|
nv->firmware_options[0] = BIT_2 | BIT_1;
|
|
|
|
nv->firmware_options[1] = BIT_7 | BIT_5;
|
|
|
|
nv->add_firmware_options[0] = BIT_5;
|
|
|
|
nv->add_firmware_options[1] = BIT_5 | BIT_4;
|
|
|
|
nv->frame_payload_size = __constant_cpu_to_le16(1024);
|
|
|
|
} else if (IS_QLA2100(ha)) {
|
|
|
|
nv->firmware_options[0] = BIT_3 | BIT_1;
|
|
|
|
nv->firmware_options[1] = BIT_5;
|
|
|
|
nv->frame_payload_size = __constant_cpu_to_le16(1024);
|
|
|
|
}
|
|
|
|
|
|
|
|
nv->max_iocb_allocation = __constant_cpu_to_le16(256);
|
|
|
|
nv->execution_throttle = __constant_cpu_to_le16(16);
|
|
|
|
nv->retry_count = 8;
|
|
|
|
nv->retry_delay = 1;
|
|
|
|
|
|
|
|
nv->port_name[0] = 33;
|
|
|
|
nv->port_name[3] = 224;
|
|
|
|
nv->port_name[4] = 139;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2xxx_nvram_wwn_from_ofw(vha, nv);
|
2007-04-16 13:37:43 -06:00
|
|
|
|
|
|
|
nv->login_timeout = 4;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set default host adapter parameters
|
|
|
|
*/
|
|
|
|
nv->host_p[1] = BIT_2;
|
|
|
|
nv->reset_delay = 5;
|
|
|
|
nv->port_down_retry_count = 8;
|
|
|
|
nv->max_luns_per_target = __constant_cpu_to_le16(8);
|
|
|
|
nv->link_down_timeout = 60;
|
|
|
|
|
|
|
|
rval = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
|
|
|
|
/*
|
|
|
|
* The SN2 does not provide BIOS emulation which means you can't change
|
|
|
|
* potentially bogus BIOS settings. Force the use of default settings
|
|
|
|
* for link rate and frame size. Hope that the rest of the settings
|
|
|
|
* are valid.
|
|
|
|
*/
|
|
|
|
if (ia64_platform_is("sn2")) {
|
|
|
|
nv->frame_payload_size = __constant_cpu_to_le16(2048);
|
|
|
|
if (IS_QLA23XX(ha))
|
|
|
|
nv->special_options[1] = BIT_7;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Reset Initialization control block */
|
2005-07-06 11:31:37 -06:00
|
|
|
memset(icb, 0, ha->init_cb_size);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup driver NVRAM options.
|
|
|
|
*/
|
|
|
|
nv->firmware_options[0] |= (BIT_6 | BIT_1);
|
|
|
|
nv->firmware_options[0] &= ~(BIT_5 | BIT_4);
|
|
|
|
nv->firmware_options[1] |= (BIT_5 | BIT_0);
|
|
|
|
nv->firmware_options[1] &= ~BIT_4;
|
|
|
|
|
|
|
|
if (IS_QLA23XX(ha)) {
|
|
|
|
nv->firmware_options[0] |= BIT_2;
|
|
|
|
nv->firmware_options[0] &= ~BIT_3;
|
2010-05-04 16:01:26 -06:00
|
|
|
nv->firmware_options[0] &= ~BIT_6;
|
2005-07-06 11:31:37 -06:00
|
|
|
nv->add_firmware_options[1] |= BIT_5 | BIT_4;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (IS_QLA2300(ha)) {
|
|
|
|
if (ha->fb_rev == FPM_2310) {
|
|
|
|
strcpy(ha->model_number, "QLA2310");
|
|
|
|
} else {
|
|
|
|
strcpy(ha->model_number, "QLA2300");
|
|
|
|
}
|
|
|
|
} else {
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_set_model_info(vha, nv->model_number,
|
2007-01-29 11:22:24 -07:00
|
|
|
sizeof(nv->model_number), "QLA23xx");
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
} else if (IS_QLA2200(ha)) {
|
|
|
|
nv->firmware_options[0] |= BIT_2;
|
|
|
|
/*
|
|
|
|
* 'Point-to-point preferred, else loop' is not a safe
|
|
|
|
* connection mode setting.
|
|
|
|
*/
|
|
|
|
if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) ==
|
|
|
|
(BIT_5 | BIT_4)) {
|
|
|
|
/* Force 'loop preferred, else point-to-point'. */
|
|
|
|
nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4);
|
|
|
|
nv->add_firmware_options[0] |= BIT_5;
|
|
|
|
}
|
|
|
|
strcpy(ha->model_number, "QLA22xx");
|
|
|
|
} else /*if (IS_QLA2100(ha))*/ {
|
|
|
|
strcpy(ha->model_number, "QLA2100");
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy over NVRAM RISC parameter block to initialization control block.
|
|
|
|
*/
|
|
|
|
dptr1 = (uint8_t *)icb;
|
|
|
|
dptr2 = (uint8_t *)&nv->parameter_block_version;
|
|
|
|
cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version;
|
|
|
|
while (cnt--)
|
|
|
|
*dptr1++ = *dptr2++;
|
|
|
|
|
|
|
|
/* Copy 2nd half. */
|
|
|
|
dptr1 = (uint8_t *)icb->add_firmware_options;
|
|
|
|
cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options;
|
|
|
|
while (cnt--)
|
|
|
|
*dptr1++ = *dptr2++;
|
|
|
|
|
2006-05-17 16:09:16 -06:00
|
|
|
/* Use alternate WWN? */
|
|
|
|
if (nv->host_p[1] & BIT_7) {
|
|
|
|
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
|
|
|
|
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Prepare nodename */
|
|
|
|
if ((icb->firmware_options[1] & BIT_6) == 0) {
|
|
|
|
/*
|
|
|
|
* Firmware will apply the following mask if the nodename was
|
|
|
|
* not provided.
|
|
|
|
*/
|
|
|
|
memcpy(icb->node_name, icb->port_name, WWN_SIZE);
|
|
|
|
icb->node_name[0] &= 0xF0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set host adapter parameters.
|
|
|
|
*/
|
2006-06-23 17:11:10 -06:00
|
|
|
if (nv->host_p[0] & BIT_7)
|
2006-10-06 10:54:59 -06:00
|
|
|
ql2xextended_error_logging = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
|
|
|
|
/* Always load RISC code on non ISP2[12]00 chips. */
|
|
|
|
if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
|
|
|
|
ha->flags.disable_risc_code_load = 0;
|
|
|
|
ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
|
|
|
|
ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
|
|
|
|
ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
|
2005-08-26 20:09:00 -06:00
|
|
|
ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0;
|
2006-06-23 17:10:39 -06:00
|
|
|
ha->flags.disable_serdes = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
ha->operating_mode =
|
|
|
|
(icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
|
|
|
|
|
|
|
|
memcpy(ha->fw_seriallink_options, nv->seriallink_options,
|
|
|
|
sizeof(ha->fw_seriallink_options));
|
|
|
|
|
|
|
|
/* save HBA serial number */
|
|
|
|
ha->serial0 = icb->port_name[5];
|
|
|
|
ha->serial1 = icb->port_name[6];
|
|
|
|
ha->serial2 = icb->port_name[7];
|
2008-11-06 11:40:51 -07:00
|
|
|
memcpy(vha->node_name, icb->node_name, WWN_SIZE);
|
|
|
|
memcpy(vha->port_name, icb->port_name, WWN_SIZE);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
|
|
|
|
|
|
|
|
ha->retry_count = nv->retry_count;
|
|
|
|
|
|
|
|
/* Set minimum login_timeout to 4 seconds. */
|
|
|
|
if (nv->login_timeout < ql2xlogintimeout)
|
|
|
|
nv->login_timeout = ql2xlogintimeout;
|
|
|
|
if (nv->login_timeout < 4)
|
|
|
|
nv->login_timeout = 4;
|
|
|
|
ha->login_timeout = nv->login_timeout;
|
|
|
|
icb->login_timeout = nv->login_timeout;
|
|
|
|
|
2008-02-28 15:06:11 -07:00
|
|
|
/* Set minimum RATOV to 100 tenths of a second. */
|
|
|
|
ha->r_a_tov = 100;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
ha->loop_reset_delay = nv->reset_delay;
|
|
|
|
|
|
|
|
/* Link Down Timeout = 0:
|
|
|
|
*
|
|
|
|
* When Port Down timer expires we will start returning
|
|
|
|
* I/O's to OS with "DID_NO_CONNECT".
|
|
|
|
*
|
|
|
|
* Link Down Timeout != 0:
|
|
|
|
*
|
|
|
|
* The driver waits for the link to come up after link down
|
|
|
|
* before returning I/Os to OS with "DID_NO_CONNECT".
|
2005-07-06 11:32:07 -06:00
|
|
|
*/
|
2005-04-16 16:20:36 -06:00
|
|
|
if (nv->link_down_timeout == 0) {
|
|
|
|
ha->loop_down_abort_time =
|
2005-04-23 00:47:27 -06:00
|
|
|
(LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
|
2005-04-16 16:20:36 -06:00
|
|
|
} else {
|
|
|
|
ha->link_down_timeout = nv->link_down_timeout;
|
|
|
|
ha->loop_down_abort_time =
|
|
|
|
(LOOP_DOWN_TIME - ha->link_down_timeout);
|
2005-07-06 11:32:07 -06:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Need enough time to try and get the port back.
|
|
|
|
*/
|
|
|
|
ha->port_down_retry_count = nv->port_down_retry_count;
|
|
|
|
if (qlport_down_retry)
|
|
|
|
ha->port_down_retry_count = qlport_down_retry;
|
|
|
|
/* Set login_retry_count */
|
|
|
|
ha->login_retry_count = nv->retry_count;
|
|
|
|
if (ha->port_down_retry_count == nv->port_down_retry_count &&
|
|
|
|
ha->port_down_retry_count > 3)
|
|
|
|
ha->login_retry_count = ha->port_down_retry_count;
|
|
|
|
else if (ha->port_down_retry_count > (int)ha->login_retry_count)
|
|
|
|
ha->login_retry_count = ha->port_down_retry_count;
|
|
|
|
if (ql2xloginretrycount)
|
|
|
|
ha->login_retry_count = ql2xloginretrycount;
|
|
|
|
|
|
|
|
icb->lun_enables = __constant_cpu_to_le16(0);
|
|
|
|
icb->command_resource_count = 0;
|
|
|
|
icb->immediate_notify_resource_count = 0;
|
|
|
|
icb->timeout = __constant_cpu_to_le16(0);
|
|
|
|
|
|
|
|
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
|
|
|
|
/* Enable RIO */
|
|
|
|
icb->firmware_options[0] &= ~BIT_3;
|
|
|
|
icb->add_firmware_options[0] &=
|
|
|
|
~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
|
|
|
|
icb->add_firmware_options[0] |= BIT_2;
|
|
|
|
icb->response_accumulation_timer = 3;
|
|
|
|
icb->interrupt_delay_timer = 5;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.process_response_queue = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
} else {
|
2005-10-27 12:09:48 -06:00
|
|
|
/* Enable ZIO. */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (!vha->flags.init_done) {
|
2005-10-27 12:09:48 -06:00
|
|
|
ha->zio_mode = icb->add_firmware_options[0] &
|
|
|
|
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
|
|
|
|
ha->zio_timer = icb->interrupt_delay_timer ?
|
|
|
|
icb->interrupt_delay_timer: 2;
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
icb->add_firmware_options[0] &=
|
|
|
|
~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.process_response_queue = 0;
|
2005-10-27 12:09:48 -06:00
|
|
|
if (ha->zio_mode != QLA_ZIO_DISABLED) {
|
2006-03-09 15:27:39 -07:00
|
|
|
ha->zio_mode = QLA_ZIO_MODE_6;
|
|
|
|
|
2005-10-27 12:09:48 -06:00
|
|
|
DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer "
|
2008-11-06 11:40:51 -07:00
|
|
|
"delay (%d us).\n", vha->host_no, ha->zio_mode,
|
2005-10-27 12:09:48 -06:00
|
|
|
ha->zio_timer * 100));
|
2005-04-16 16:20:36 -06:00
|
|
|
qla_printk(KERN_INFO, ha,
|
2005-10-27 12:09:48 -06:00
|
|
|
"ZIO mode %d enabled; timer delay (%d us).\n",
|
|
|
|
ha->zio_mode, ha->zio_timer * 100);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-10-27 12:09:48 -06:00
|
|
|
icb->add_firmware_options[0] |= (uint8_t)ha->zio_mode;
|
|
|
|
icb->interrupt_delay_timer = (uint8_t)ha->zio_timer;
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.process_response_queue = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-16 13:37:43 -06:00
|
|
|
if (rval) {
|
|
|
|
DEBUG2_3(printk(KERN_WARNING
|
2008-11-06 11:40:51 -07:00
|
|
|
"scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
|
2007-04-16 13:37:43 -06:00
|
|
|
}
|
|
|
|
return (rval);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
[SCSI] update fc_transport for removal of block/unblock functions
We recently went back to implement a board reset. When we perform the
reset, we wanted to tear down the internal data structures and rebuild
them. Unfortunately, when it came to the rport structure, things were
odd. If we deleted them, the scsi targets and sdevs would be
torn down. Not a good thing for a temporary reset. We could block the
rports, but we either maintain the internal structures to keep the
rport reference (perhaps even replicating what's in the transport),
or we have to fatten the fc transport with new search routines to find
the rport (and deal with a case of a dangling rport that the driver
forgets).
It dawned on me that we had actually reached this state incorrectly.
When the fc transport first started, we did the block/unblock first, then
added the rport interface. The purpose of block/unblock is to hide the
temporary disappearance of the rport (e.g. being deleted, then readded).
Why are we making the driver do the block/unblock ? We should be making
the transport have only an rport add/delete, and the let the transport
handle the block/unblock.
So... This patch removes the existing fc_remote_port_block/unblock
functions. It moves the block/unblock functionality into the
fc_remote_port_add/delete functions. Updates for the lpfc driver are
included. Qlogic driver updates are also enclosed, thanks to the
contributions of Andrew Vasquez. [Note: the qla2xxx changes are
relative to the scsi-misc-2.6 tree as of this morning - which does
not include the recent patches sent by Andrew]. The zfcp driver does
not use the block/unblock functions.
One last comment: The resulting behavior feels very clean. The LLDD is
concerned only with add/delete, which corresponds to the physical
disappearance. However, the fact that the scsi target and sdevs are
not immediately torn down after the LLDD calls delete causes an
interesting scenario... the midlayer can call the xxx_slave_alloc and
xxx_queuecommand functions with a sdev that is at the location the
rport used to be. The driver must validate the device exists when it
first enters these functions. In thinking about it, this has always
been the case for the LLDD and these routines. The existing drivers
already check for existence. However, this highlights that simple
validation via data structure dereferencing needs to be watched.
To deal with this, a new transport function, fc_remote_port_chkready()
was created that LLDDs should call when they first enter these two
routines. It validates the rport state, and returns a scsi result
which could be returned. In addition to solving the above, it also
creates consistent behavior from the LLDD's when the block and deletes
are occuring.
Rejections fixed up and
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-10-18 10:03:35 -06:00
|
|
|
static void
|
|
|
|
qla2x00_rport_del(void *data)
|
|
|
|
{
|
|
|
|
fc_port_t *fcport = data;
|
2006-01-20 15:53:13 -07:00
|
|
|
struct fc_rport *rport;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
spin_lock_irq(fcport->vha->host->host_lock);
|
2009-08-20 12:06:05 -06:00
|
|
|
rport = fcport->drport ? fcport->drport: fcport->rport;
|
2006-01-20 15:53:13 -07:00
|
|
|
fcport->drport = NULL;
|
2008-11-06 11:40:51 -07:00
|
|
|
spin_unlock_irq(fcport->vha->host->host_lock);
|
2006-01-20 15:53:13 -07:00
|
|
|
if (rport)
|
|
|
|
fc_remote_port_delete(rport);
|
[SCSI] update fc_transport for removal of block/unblock functions
We recently went back to implement a board reset. When we perform the
reset, we wanted to tear down the internal data structures and rebuild
them. Unfortunately, when it came to the rport structure, things were
odd. If we deleted them, the scsi targets and sdevs would be
torn down. Not a good thing for a temporary reset. We could block the
rports, but we either maintain the internal structures to keep the
rport reference (perhaps even replicating what's in the transport),
or we have to fatten the fc transport with new search routines to find
the rport (and deal with a case of a dangling rport that the driver
forgets).
It dawned on me that we had actually reached this state incorrectly.
When the fc transport first started, we did the block/unblock first, then
added the rport interface. The purpose of block/unblock is to hide the
temporary disappearance of the rport (e.g. being deleted, then readded).
Why are we making the driver do the block/unblock ? We should be making
the transport have only an rport add/delete, and the let the transport
handle the block/unblock.
So... This patch removes the existing fc_remote_port_block/unblock
functions. It moves the block/unblock functionality into the
fc_remote_port_add/delete functions. Updates for the lpfc driver are
included. Qlogic driver updates are also enclosed, thanks to the
contributions of Andrew Vasquez. [Note: the qla2xxx changes are
relative to the scsi-misc-2.6 tree as of this morning - which does
not include the recent patches sent by Andrew]. The zfcp driver does
not use the block/unblock functions.
One last comment: The resulting behavior feels very clean. The LLDD is
concerned only with add/delete, which corresponds to the physical
disappearance. However, the fact that the scsi target and sdevs are
not immediately torn down after the LLDD calls delete causes an
interesting scenario... the midlayer can call the xxx_slave_alloc and
xxx_queuecommand functions with a sdev that is at the location the
rport used to be. The driver must validate the device exists when it
first enters these functions. In thinking about it, this has always
been the case for the LLDD and these routines. The existing drivers
already check for existence. However, this highlights that simple
validation via data structure dereferencing needs to be watched.
To deal with this, a new transport function, fc_remote_port_chkready()
was created that LLDDs should call when they first enter these two
routines. It validates the rport state, and returns a scsi result
which could be returned. In addition to solving the above, it also
creates consistent behavior from the LLDD's when the block and deletes
are occuring.
Rejections fixed up and
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-10-18 10:03:35 -06:00
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/**
|
|
|
|
* qla2x00_alloc_fcport() - Allocate a generic fcport.
|
|
|
|
* @ha: HA context
|
|
|
|
* @flags: allocation flags
|
|
|
|
*
|
|
|
|
* Returns a pointer to the allocated fcport, or NULL, if none available.
|
|
|
|
*/
|
2010-01-12 14:02:47 -07:00
|
|
|
fc_port_t *
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
fc_port_t *fcport;
|
|
|
|
|
[SCSI] kmalloc + memset conversion to kzalloc
In NCR_D700, a4000t, aic7xxx_old, bvme6000, dpt_i2o, gdth, lpfc,
megaraid, mvme16x osst, pluto, qla2xxx, zorro7xx
Signed-off-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2007-08-11 02:13:24 -06:00
|
|
|
fcport = kzalloc(sizeof(fc_port_t), flags);
|
|
|
|
if (!fcport)
|
|
|
|
return NULL;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Setup fcport template structure. */
|
2008-11-06 11:40:51 -07:00
|
|
|
fcport->vha = vha;
|
|
|
|
fcport->vp_idx = vha->vp_idx;
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->port_type = FCT_UNKNOWN;
|
|
|
|
fcport->loop_id = FC_NO_LOOP_ID;
|
|
|
|
atomic_set(&fcport->state, FCS_UNCONFIGURED);
|
2005-08-26 20:08:10 -06:00
|
|
|
fcport->supported_classes = FC_COS_UNSPECIFIED;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
[SCSI] kmalloc + memset conversion to kzalloc
In NCR_D700, a4000t, aic7xxx_old, bvme6000, dpt_i2o, gdth, lpfc,
megaraid, mvme16x osst, pluto, qla2xxx, zorro7xx
Signed-off-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2007-08-11 02:13:24 -06:00
|
|
|
return fcport;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_configure_loop
|
|
|
|
* Updates Fibre Channel Device Database with what is actually on loop.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success.
|
|
|
|
* 1 = error.
|
|
|
|
* 2 = database was full and device was not configured.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_configure_loop(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
unsigned long flags, save_flags;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-16 16:20:36 -06:00
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
|
|
|
|
/* Get Initiator ID */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (test_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags)) {
|
|
|
|
rval = qla2x00_configure_hba(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
DEBUG(printk("scsi(%ld): Unable to configure HBA.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
save_flags = flags = vha->dpc_flags;
|
2005-04-16 16:20:36 -06:00
|
|
|
DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, flags));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have both an RSCN and PORT UPDATE pending then handle them
|
|
|
|
* both at the same time.
|
|
|
|
*/
|
2008-11-06 11:40:51 -07:00
|
|
|
clear_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
|
|
|
|
clear_bit(RSCN_UPDATE, &vha->dpc_flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-12-15 22:29:44 -07:00
|
|
|
qla2x00_get_data_rate(vha);
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Determine what we need to do */
|
|
|
|
if (ha->current_topology == ISP_CFG_FL &&
|
|
|
|
(test_bit(LOCAL_LOOP_UPDATE, &flags))) {
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.rscn_queue_overflow = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
set_bit(RSCN_UPDATE, &flags);
|
|
|
|
|
|
|
|
} else if (ha->current_topology == ISP_CFG_F &&
|
|
|
|
(test_bit(LOCAL_LOOP_UPDATE, &flags))) {
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.rscn_queue_overflow = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
set_bit(RSCN_UPDATE, &flags);
|
|
|
|
clear_bit(LOCAL_LOOP_UPDATE, &flags);
|
2006-05-17 16:09:56 -06:00
|
|
|
|
|
|
|
} else if (ha->current_topology == ISP_CFG_N) {
|
|
|
|
clear_bit(RSCN_UPDATE, &flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
} else if (!vha->flags.online ||
|
2005-04-16 16:20:36 -06:00
|
|
|
(test_bit(ABORT_ISP_ACTIVE, &flags))) {
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.rscn_queue_overflow = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
set_bit(RSCN_UPDATE, &flags);
|
|
|
|
set_bit(LOCAL_LOOP_UPDATE, &flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
|
2008-11-06 11:40:51 -07:00
|
|
|
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
rval = QLA_FUNCTION_FAILED;
|
2008-11-06 11:40:51 -07:00
|
|
|
else
|
|
|
|
rval = qla2x00_configure_local_loop(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
|
2008-11-06 11:40:51 -07:00
|
|
|
if (LOOP_TRANSITION(vha))
|
2005-04-16 16:20:36 -06:00
|
|
|
rval = QLA_FUNCTION_FAILED;
|
2008-11-06 11:40:51 -07:00
|
|
|
else
|
|
|
|
rval = qla2x00_configure_fabric(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rval == QLA_SUCCESS) {
|
2008-11-06 11:40:51 -07:00
|
|
|
if (atomic_read(&vha->loop_down_timer) ||
|
|
|
|
test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
|
2005-04-16 16:20:36 -06:00
|
|
|
rval = QLA_FUNCTION_FAILED;
|
|
|
|
} else {
|
2008-11-06 11:40:51 -07:00
|
|
|
atomic_set(&vha->loop_state, LOOP_READY);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
DEBUG(printk("scsi(%ld): LOOP READY\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rval) {
|
|
|
|
DEBUG2_3(printk("%s(%ld): *** FAILED ***\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
__func__, vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
} else {
|
|
|
|
DEBUG3(printk("%s: exiting normally\n", __func__));
|
|
|
|
}
|
|
|
|
|
2008-09-11 22:22:51 -06:00
|
|
|
/* Restore state if a resync event occurred during processing */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) {
|
2005-04-16 16:20:36 -06:00
|
|
|
if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
|
2008-11-06 11:40:51 -07:00
|
|
|
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
|
2009-06-03 10:55:21 -06:00
|
|
|
if (test_bit(RSCN_UPDATE, &save_flags)) {
|
2008-11-06 11:40:51 -07:00
|
|
|
set_bit(RSCN_UPDATE, &vha->dpc_flags);
|
2009-06-03 10:55:21 -06:00
|
|
|
vha->flags.rscn_queue_overflow = 1;
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_configure_local_loop
|
|
|
|
* Updates Fibre Channel Device Database with local loop devices.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_configure_local_loop(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval, rval2;
|
|
|
|
int found_devs;
|
|
|
|
int found;
|
|
|
|
fc_port_t *fcport, *new_fcport;
|
|
|
|
|
|
|
|
uint16_t index;
|
|
|
|
uint16_t entries;
|
|
|
|
char *id_iter;
|
|
|
|
uint16_t loop_id;
|
|
|
|
uint8_t domain, area, al_pa;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
found_devs = 0;
|
|
|
|
new_fcport = NULL;
|
|
|
|
entries = MAX_FIBRE_DEVICES;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", vha->host_no));
|
|
|
|
DEBUG3(qla2x00_get_fcal_position_map(vha, NULL));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Get list of logged in devices. */
|
|
|
|
memset(ha->gid_list, 0, GID_LIST_SIZE);
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_get_id_list(vha, ha->gid_list, ha->gid_list_dma,
|
2005-04-16 16:20:36 -06:00
|
|
|
&entries);
|
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
goto cleanup_allocation;
|
|
|
|
|
|
|
|
DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
|
2009-04-06 23:33:39 -06:00
|
|
|
vha->host_no, entries));
|
2005-04-16 16:20:36 -06:00
|
|
|
DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
|
|
|
|
entries * sizeof(struct gid_list_info)));
|
|
|
|
|
|
|
|
/* Allocate temporary fcport for any new fcports discovered. */
|
2008-11-06 11:40:51 -07:00
|
|
|
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (new_fcport == NULL) {
|
|
|
|
rval = QLA_MEMORY_ALLOC_FAILED;
|
|
|
|
goto cleanup_allocation;
|
|
|
|
}
|
|
|
|
new_fcport->flags &= ~FCF_FABRIC_DEVICE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark local devices that were present with FCF_DEVICE_LOST for now.
|
|
|
|
*/
|
2008-11-06 11:40:51 -07:00
|
|
|
list_for_each_entry(fcport, &vha->vp_fcports, list) {
|
2005-04-16 16:20:36 -06:00
|
|
|
if (atomic_read(&fcport->state) == FCS_ONLINE &&
|
|
|
|
fcport->port_type != FCT_BROADCAST &&
|
|
|
|
(fcport->flags & FCF_FABRIC_DEVICE) == 0) {
|
|
|
|
|
|
|
|
DEBUG(printk("scsi(%ld): Marking port lost, "
|
|
|
|
"loop_id=0x%04x\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, fcport->loop_id));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
atomic_set(&fcport->state, FCS_DEVICE_LOST);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add devices to port list. */
|
|
|
|
id_iter = (char *)ha->gid_list;
|
|
|
|
for (index = 0; index < entries; index++) {
|
|
|
|
domain = ((struct gid_list_info *)id_iter)->domain;
|
|
|
|
area = ((struct gid_list_info *)id_iter)->area;
|
|
|
|
al_pa = ((struct gid_list_info *)id_iter)->al_pa;
|
2005-07-06 11:30:05 -06:00
|
|
|
if (IS_QLA2100(ha) || IS_QLA2200(ha))
|
2005-04-16 16:20:36 -06:00
|
|
|
loop_id = (uint16_t)
|
|
|
|
((struct gid_list_info *)id_iter)->loop_id_2100;
|
2005-07-06 11:30:05 -06:00
|
|
|
else
|
2005-04-16 16:20:36 -06:00
|
|
|
loop_id = le16_to_cpu(
|
|
|
|
((struct gid_list_info *)id_iter)->loop_id);
|
2005-07-06 11:30:05 -06:00
|
|
|
id_iter += ha->gid_list_info_size;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Bypass reserved domain fields. */
|
|
|
|
if ((domain & 0xf0) == 0xf0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Bypass if not same domain and area of adapter. */
|
2005-08-26 20:08:40 -06:00
|
|
|
if (area && domain &&
|
2008-11-06 11:40:51 -07:00
|
|
|
(area != vha->d_id.b.area || domain != vha->d_id.b.domain))
|
2005-04-16 16:20:36 -06:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Bypass invalid local loop ID. */
|
|
|
|
if (loop_id > LAST_LOCAL_LOOP_ID)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Fill in member data. */
|
|
|
|
new_fcport->d_id.b.domain = domain;
|
|
|
|
new_fcport->d_id.b.area = area;
|
|
|
|
new_fcport->d_id.b.al_pa = al_pa;
|
|
|
|
new_fcport->loop_id = loop_id;
|
2008-11-06 11:40:51 -07:00
|
|
|
new_fcport->vp_idx = vha->vp_idx;
|
|
|
|
rval2 = qla2x00_get_port_database(vha, new_fcport, 0);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval2 != QLA_SUCCESS) {
|
|
|
|
DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
|
|
|
|
"information -- get_port_database=%x, "
|
|
|
|
"loop_id=0x%04x\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, rval2, new_fcport->loop_id));
|
2006-01-13 18:05:26 -07:00
|
|
|
DEBUG2(printk("scsi(%ld): Scheduling resync...\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no));
|
|
|
|
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for matching device in port list. */
|
|
|
|
found = 0;
|
|
|
|
fcport = NULL;
|
2008-11-06 11:40:51 -07:00
|
|
|
list_for_each_entry(fcport, &vha->vp_fcports, list) {
|
2005-04-16 16:20:36 -06:00
|
|
|
if (memcmp(new_fcport->port_name, fcport->port_name,
|
|
|
|
WWN_SIZE))
|
|
|
|
continue;
|
|
|
|
|
2009-03-24 10:08:10 -06:00
|
|
|
fcport->flags &= ~FCF_FABRIC_DEVICE;
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->loop_id = new_fcport->loop_id;
|
|
|
|
fcport->port_type = new_fcport->port_type;
|
|
|
|
fcport->d_id.b24 = new_fcport->d_id.b24;
|
|
|
|
memcpy(fcport->node_name, new_fcport->node_name,
|
|
|
|
WWN_SIZE);
|
|
|
|
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
/* New device, add to fcports list. */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (vha->vp_idx) {
|
|
|
|
new_fcport->vha = vha;
|
|
|
|
new_fcport->vp_idx = vha->vp_idx;
|
2007-07-05 14:16:51 -06:00
|
|
|
}
|
2008-11-06 11:40:51 -07:00
|
|
|
list_add_tail(&new_fcport->list, &vha->vp_fcports);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Allocate a new replacement fcport. */
|
|
|
|
fcport = new_fcport;
|
2008-11-06 11:40:51 -07:00
|
|
|
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (new_fcport == NULL) {
|
|
|
|
rval = QLA_MEMORY_ALLOC_FAILED;
|
|
|
|
goto cleanup_allocation;
|
|
|
|
}
|
|
|
|
new_fcport->flags &= ~FCF_FABRIC_DEVICE;
|
|
|
|
}
|
|
|
|
|
2006-10-02 13:00:43 -06:00
|
|
|
/* Base iIDMA settings on HBA port speed. */
|
2007-08-13 11:13:18 -06:00
|
|
|
fcport->fp_speed = ha->link_data_rate;
|
2006-10-02 13:00:43 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_update_fcport(vha, fcport);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
found_devs++;
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup_allocation:
|
2005-11-07 02:01:26 -07:00
|
|
|
kfree(new_fcport);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
DEBUG2(printk("scsi(%ld): Configure local loop error exit: "
|
2008-11-06 11:40:51 -07:00
|
|
|
"rval=%x\n", vha->host_no, rval));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
2006-10-02 13:00:43 -06:00
|
|
|
static void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
|
2006-10-02 13:00:43 -06:00
|
|
|
{
|
|
|
|
#define LS_UNKNOWN 2
|
2009-06-03 10:55:22 -06:00
|
|
|
static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" };
|
|
|
|
char *link_speed;
|
2006-10-02 13:00:43 -06:00
|
|
|
int rval;
|
2009-06-17 11:30:29 -06:00
|
|
|
uint16_t mb[4];
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2006-10-02 13:00:43 -06:00
|
|
|
|
2007-07-19 16:05:57 -06:00
|
|
|
if (!IS_IIDMA_CAPABLE(ha))
|
2006-10-02 13:00:43 -06:00
|
|
|
return;
|
|
|
|
|
2007-09-20 15:07:34 -06:00
|
|
|
if (fcport->fp_speed == PORT_SPEED_UNKNOWN ||
|
|
|
|
fcport->fp_speed > ha->link_data_rate)
|
2006-10-02 13:00:43 -06:00
|
|
|
return;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed,
|
2007-08-13 11:13:18 -06:00
|
|
|
mb);
|
2006-10-02 13:00:43 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
|
|
|
|
"%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, fcport->port_name[0], fcport->port_name[1],
|
2006-10-02 13:00:43 -06:00
|
|
|
fcport->port_name[2], fcport->port_name[3],
|
|
|
|
fcport->port_name[4], fcport->port_name[5],
|
|
|
|
fcport->port_name[6], fcport->port_name[7], rval,
|
2007-08-13 11:13:18 -06:00
|
|
|
fcport->fp_speed, mb[0], mb[1]));
|
2006-10-02 13:00:43 -06:00
|
|
|
} else {
|
2009-06-03 10:55:22 -06:00
|
|
|
link_speed = link_speeds[LS_UNKNOWN];
|
|
|
|
if (fcport->fp_speed < 5)
|
|
|
|
link_speed = link_speeds[fcport->fp_speed];
|
|
|
|
else if (fcport->fp_speed == 0x13)
|
|
|
|
link_speed = link_speeds[5];
|
2006-10-02 13:00:43 -06:00
|
|
|
DEBUG2(qla_printk(KERN_INFO, ha,
|
|
|
|
"iIDMA adjusted to %s GB/s on "
|
|
|
|
"%02x%02x%02x%02x%02x%02x%02x%02x.\n",
|
2009-06-03 10:55:22 -06:00
|
|
|
link_speed, fcport->port_name[0],
|
2006-10-02 13:00:43 -06:00
|
|
|
fcport->port_name[1], fcport->port_name[2],
|
|
|
|
fcport->port_name[3], fcport->port_name[4],
|
|
|
|
fcport->port_name[5], fcport->port_name[6],
|
|
|
|
fcport->port_name[7]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-11-23 18:46:01 -07:00
|
|
|
static void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
|
2005-04-17 14:04:54 -06:00
|
|
|
{
|
|
|
|
struct fc_rport_identifiers rport_ids;
|
2005-04-17 14:06:53 -06:00
|
|
|
struct fc_rport *rport;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-17 14:04:54 -06:00
|
|
|
|
2009-08-20 12:06:05 -06:00
|
|
|
qla2x00_rport_del(fcport);
|
2005-04-17 14:04:54 -06:00
|
|
|
|
2005-08-31 16:21:20 -06:00
|
|
|
rport_ids.node_name = wwn_to_u64(fcport->node_name);
|
|
|
|
rport_ids.port_name = wwn_to_u64(fcport->port_name);
|
2005-04-17 14:04:54 -06:00
|
|
|
rport_ids.port_id = fcport->d_id.b.domain << 16 |
|
|
|
|
fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
|
2005-07-08 19:00:36 -06:00
|
|
|
rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
|
2008-11-06 11:40:51 -07:00
|
|
|
fcport->rport = rport = fc_remote_port_add(vha->host, 0, &rport_ids);
|
2005-07-08 19:00:36 -06:00
|
|
|
if (!rport) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to allocate fc remote port!\n");
|
|
|
|
return;
|
|
|
|
}
|
2008-11-06 11:40:51 -07:00
|
|
|
spin_lock_irq(fcport->vha->host->host_lock);
|
[SCSI] update fc_transport for removal of block/unblock functions
We recently went back to implement a board reset. When we perform the
reset, we wanted to tear down the internal data structures and rebuild
them. Unfortunately, when it came to the rport structure, things were
odd. If we deleted them, the scsi targets and sdevs would be
torn down. Not a good thing for a temporary reset. We could block the
rports, but we either maintain the internal structures to keep the
rport reference (perhaps even replicating what's in the transport),
or we have to fatten the fc transport with new search routines to find
the rport (and deal with a case of a dangling rport that the driver
forgets).
It dawned on me that we had actually reached this state incorrectly.
When the fc transport first started, we did the block/unblock first, then
added the rport interface. The purpose of block/unblock is to hide the
temporary disappearance of the rport (e.g. being deleted, then readded).
Why are we making the driver do the block/unblock ? We should be making
the transport have only an rport add/delete, and the let the transport
handle the block/unblock.
So... This patch removes the existing fc_remote_port_block/unblock
functions. It moves the block/unblock functionality into the
fc_remote_port_add/delete functions. Updates for the lpfc driver are
included. Qlogic driver updates are also enclosed, thanks to the
contributions of Andrew Vasquez. [Note: the qla2xxx changes are
relative to the scsi-misc-2.6 tree as of this morning - which does
not include the recent patches sent by Andrew]. The zfcp driver does
not use the block/unblock functions.
One last comment: The resulting behavior feels very clean. The LLDD is
concerned only with add/delete, which corresponds to the physical
disappearance. However, the fact that the scsi target and sdevs are
not immediately torn down after the LLDD calls delete causes an
interesting scenario... the midlayer can call the xxx_slave_alloc and
xxx_queuecommand functions with a sdev that is at the location the
rport used to be. The driver must validate the device exists when it
first enters these functions. In thinking about it, this has always
been the case for the LLDD and these routines. The existing drivers
already check for existence. However, this highlights that simple
validation via data structure dereferencing needs to be watched.
To deal with this, a new transport function, fc_remote_port_chkready()
was created that LLDDs should call when they first enter these two
routines. It validates the rport state, and returns a scsi result
which could be returned. In addition to solving the above, it also
creates consistent behavior from the LLDD's when the block and deletes
are occuring.
Rejections fixed up and
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2005-10-18 10:03:35 -06:00
|
|
|
*((fc_port_t **)rport->dd_data) = fcport;
|
2008-11-06 11:40:51 -07:00
|
|
|
spin_unlock_irq(fcport->vha->host->host_lock);
|
2006-01-20 15:53:13 -07:00
|
|
|
|
2005-08-26 20:08:10 -06:00
|
|
|
rport->supported_classes = fcport->supported_classes;
|
2005-07-08 19:00:36 -06:00
|
|
|
|
2005-04-17 14:04:54 -06:00
|
|
|
rport_ids.roles = FC_RPORT_ROLE_UNKNOWN;
|
|
|
|
if (fcport->port_type == FCT_INITIATOR)
|
|
|
|
rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
|
|
|
if (fcport->port_type == FCT_TARGET)
|
|
|
|
rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
|
2005-07-08 19:00:36 -06:00
|
|
|
fc_remote_port_rolechg(rport, rport_ids.roles);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2006-11-23 18:46:01 -07:00
|
|
|
/*
|
|
|
|
* qla2x00_update_fcport
|
|
|
|
* Updates device on list.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
* fcport = port structure pointer.
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* 0 - Success
|
|
|
|
* BIT_0 - error
|
|
|
|
*
|
|
|
|
* Context:
|
|
|
|
* Kernel context.
|
|
|
|
*/
|
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
|
2006-11-23 18:46:01 -07:00
|
|
|
{
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2007-07-05 14:16:51 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
fcport->vha = vha;
|
2006-11-23 18:46:01 -07:00
|
|
|
fcport->login_retry = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
fcport->port_login_retry_count = ha->port_down_retry_count *
|
2006-11-23 18:46:01 -07:00
|
|
|
PORT_RETRY_TIME;
|
2008-11-06 11:40:51 -07:00
|
|
|
atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
|
2006-11-23 18:46:01 -07:00
|
|
|
PORT_RETRY_TIME);
|
2010-05-04 16:01:26 -06:00
|
|
|
fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
|
2006-11-23 18:46:01 -07:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_iidma_fcport(vha, fcport);
|
2006-11-23 18:46:01 -07:00
|
|
|
|
|
|
|
atomic_set(&fcport->state, FCS_ONLINE);
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_reg_remote_port(vha, fcport);
|
2006-11-23 18:46:01 -07:00
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/*
|
|
|
|
* qla2x00_configure_fabric
|
|
|
|
* Setup SNS devices with loop ID's.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success.
|
|
|
|
* BIT_0 = error
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_configure_fabric(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval, rval2;
|
|
|
|
fc_port_t *fcport, *fcptemp;
|
|
|
|
uint16_t next_loopid;
|
|
|
|
uint16_t mb[MAILBOX_REGISTER_COUNT];
|
2005-07-06 11:31:37 -06:00
|
|
|
uint16_t loop_id;
|
2005-04-16 16:20:36 -06:00
|
|
|
LIST_HEAD(new_fcports);
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* If FL port exists, then SNS is present */
|
2007-07-19 16:05:56 -06:00
|
|
|
if (IS_FWI2_CAPABLE(ha))
|
2005-07-06 11:31:37 -06:00
|
|
|
loop_id = NPH_F_PORT;
|
|
|
|
else
|
|
|
|
loop_id = SNS_FL_PORT;
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_node_name, 1);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
|
2008-11-06 11:40:51 -07:00
|
|
|
"Port\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->device_flags &= ~SWITCH_FOUND;
|
2005-04-16 16:20:36 -06:00
|
|
|
return (QLA_SUCCESS);
|
|
|
|
}
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->device_flags |= SWITCH_FOUND;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Mark devices that need re-synchronization. */
|
2008-11-06 11:40:51 -07:00
|
|
|
rval2 = qla2x00_device_resync(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval2 == QLA_RSCNS_HANDLED) {
|
|
|
|
/* No point doing the scan, just continue. */
|
|
|
|
return (QLA_SUCCESS);
|
|
|
|
}
|
|
|
|
do {
|
2005-08-26 20:08:30 -06:00
|
|
|
/* FDMI support. */
|
|
|
|
if (ql2xfdmienable &&
|
2008-11-06 11:40:51 -07:00
|
|
|
test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags))
|
|
|
|
qla2x00_fdmi_register(vha);
|
2005-08-26 20:08:30 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Ensure we are logged into the SNS. */
|
2007-07-19 16:05:56 -06:00
|
|
|
if (IS_FWI2_CAPABLE(ha))
|
2005-07-06 11:31:37 -06:00
|
|
|
loop_id = NPH_SNS;
|
|
|
|
else
|
|
|
|
loop_id = SIMPLE_NAME_SERVER;
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff,
|
2005-07-06 11:30:05 -06:00
|
|
|
0xfc, mb, BIT_1 | BIT_0);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (mb[0] != MBS_COMMAND_COMPLETE) {
|
|
|
|
DEBUG2(qla_printk(KERN_INFO, ha,
|
|
|
|
"Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
|
2005-07-06 11:31:37 -06:00
|
|
|
"mb[2]=%x mb[6]=%x mb[7]=%x\n", loop_id,
|
2005-04-16 16:20:36 -06:00
|
|
|
mb[0], mb[1], mb[2], mb[6], mb[7]));
|
|
|
|
return (QLA_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) {
|
|
|
|
if (qla2x00_rft_id(vha)) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/* EMPTY */
|
|
|
|
DEBUG2(printk("scsi(%ld): Register FC-4 "
|
2008-11-06 11:40:51 -07:00
|
|
|
"TYPE failed.\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2008-11-06 11:40:51 -07:00
|
|
|
if (qla2x00_rff_id(vha)) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/* EMPTY */
|
|
|
|
DEBUG2(printk("scsi(%ld): Register FC-4 "
|
2008-11-06 11:40:51 -07:00
|
|
|
"Features failed.\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2008-11-06 11:40:51 -07:00
|
|
|
if (qla2x00_rnn_id(vha)) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/* EMPTY */
|
|
|
|
DEBUG2(printk("scsi(%ld): Register Node Name "
|
2008-11-06 11:40:51 -07:00
|
|
|
"failed.\n", vha->host_no));
|
|
|
|
} else if (qla2x00_rsnn_nn(vha)) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/* EMPTY */
|
|
|
|
DEBUG2(printk("scsi(%ld): Register Symbolic "
|
2008-11-06 11:40:51 -07:00
|
|
|
"Node Name failed.\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_find_all_fabric_devs(vha, &new_fcports);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Logout all previous fabric devices marked lost, except
|
2010-01-12 13:59:48 -07:00
|
|
|
* FCP2 devices.
|
2005-04-16 16:20:36 -06:00
|
|
|
*/
|
2008-11-06 11:40:51 -07:00
|
|
|
list_for_each_entry(fcport, &vha->vp_fcports, list) {
|
|
|
|
if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_mark_device_lost(vha, fcport,
|
2006-01-20 15:53:13 -07:00
|
|
|
ql2xplogiabsentdevice, 0);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (fcport->loop_id != FC_NO_LOOP_ID &&
|
2010-01-12 13:59:48 -07:00
|
|
|
(fcport->flags & FCF_FCP2_DEVICE) == 0 &&
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->port_type != FCT_INITIATOR &&
|
|
|
|
fcport->port_type != FCT_BROADCAST) {
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->fabric_logout(vha,
|
2005-07-06 11:30:57 -06:00
|
|
|
fcport->loop_id,
|
|
|
|
fcport->d_id.b.domain,
|
|
|
|
fcport->d_id.b.area,
|
|
|
|
fcport->d_id.b.al_pa);
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->loop_id = FC_NO_LOOP_ID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Starting free loop ID. */
|
2008-11-06 11:40:51 -07:00
|
|
|
next_loopid = ha->min_external_loopid;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Scan through our port list and login entries that need to be
|
|
|
|
* logged in.
|
|
|
|
*/
|
2008-11-06 11:40:51 -07:00
|
|
|
list_for_each_entry(fcport, &vha->vp_fcports, list) {
|
|
|
|
if (atomic_read(&vha->loop_down_timer) ||
|
|
|
|
test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
|
|
|
|
(fcport->flags & FCF_LOGIN_NEEDED) == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (fcport->loop_id == FC_NO_LOOP_ID) {
|
|
|
|
fcport->loop_id = next_loopid;
|
2008-04-03 14:13:28 -06:00
|
|
|
rval = qla2x00_find_new_loop_id(
|
2008-11-06 11:40:51 -07:00
|
|
|
base_vha, fcport);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
/* Ran out of IDs to use */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Login and update database */
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Exit if out of loop IDs. */
|
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Login and add the new devices to our port list.
|
|
|
|
*/
|
|
|
|
list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
|
2008-11-06 11:40:51 -07:00
|
|
|
if (atomic_read(&vha->loop_down_timer) ||
|
|
|
|
test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
/* Find a new loop ID to use. */
|
|
|
|
fcport->loop_id = next_loopid;
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_find_new_loop_id(base_vha, fcport);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
/* Ran out of IDs to use */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2005-04-17 14:06:53 -06:00
|
|
|
/* Login and update database */
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_fabric_dev_login(vha, fcport, &next_loopid);
|
|
|
|
|
|
|
|
if (vha->vp_idx) {
|
|
|
|
fcport->vha = vha;
|
|
|
|
fcport->vp_idx = vha->vp_idx;
|
|
|
|
}
|
|
|
|
list_move_tail(&fcport->list, &vha->vp_fcports);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
/* Free all new device structures not processed. */
|
|
|
|
list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
|
|
|
|
list_del(&fcport->list);
|
|
|
|
kfree(fcport);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rval) {
|
|
|
|
DEBUG2(printk("scsi(%ld): Configure fabric error exit: "
|
2008-11-06 11:40:51 -07:00
|
|
|
"rval=%d\n", vha->host_no, rval));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_find_all_fabric_devs
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
* dev = database device entry pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success.
|
|
|
|
*
|
|
|
|
* Context:
|
|
|
|
* Kernel context.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha,
|
|
|
|
struct list_head *new_fcports)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
uint16_t loop_id;
|
|
|
|
fc_port_t *fcport, *new_fcport, *fcptemp;
|
|
|
|
int found;
|
|
|
|
|
|
|
|
sw_info_t *swl;
|
|
|
|
int swl_idx;
|
|
|
|
int first_dev, last_dev;
|
2010-05-04 16:01:31 -06:00
|
|
|
port_id_t wrap = {}, nxt_d_id;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
|
2009-03-05 12:07:02 -07:00
|
|
|
struct scsi_qla_host *tvp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
|
|
|
|
/* Try GID_PT to get device list, else GAN. */
|
2008-09-11 22:22:48 -06:00
|
|
|
swl = kcalloc(MAX_FIBRE_DEVICES, sizeof(sw_info_t), GFP_KERNEL);
|
[SCSI] kmalloc + memset conversion to kzalloc
In NCR_D700, a4000t, aic7xxx_old, bvme6000, dpt_i2o, gdth, lpfc,
megaraid, mvme16x osst, pluto, qla2xxx, zorro7xx
Signed-off-by: Mariusz Kozlowski <m.kozlowski@tuxland.pl>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
2007-08-11 02:13:24 -06:00
|
|
|
if (!swl) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/*EMPTY*/
|
|
|
|
DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
|
2008-11-06 11:40:51 -07:00
|
|
|
"on GA_NXT\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
} else {
|
2008-11-06 11:40:51 -07:00
|
|
|
if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) {
|
2005-04-16 16:20:36 -06:00
|
|
|
kfree(swl);
|
|
|
|
swl = NULL;
|
2008-11-06 11:40:51 -07:00
|
|
|
} else if (qla2x00_gpn_id(vha, swl) != QLA_SUCCESS) {
|
2005-04-16 16:20:36 -06:00
|
|
|
kfree(swl);
|
|
|
|
swl = NULL;
|
2008-11-06 11:40:51 -07:00
|
|
|
} else if (qla2x00_gnn_id(vha, swl) != QLA_SUCCESS) {
|
2005-04-16 16:20:36 -06:00
|
|
|
kfree(swl);
|
|
|
|
swl = NULL;
|
2008-07-10 17:55:52 -06:00
|
|
|
} else if (ql2xiidmaenable &&
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_gfpn_id(vha, swl) == QLA_SUCCESS) {
|
|
|
|
qla2x00_gpsc(vha, swl);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
swl_idx = 0;
|
|
|
|
|
|
|
|
/* Allocate temporary fcport for any new fcports discovered. */
|
2008-11-06 11:40:51 -07:00
|
|
|
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (new_fcport == NULL) {
|
2005-11-07 02:01:26 -07:00
|
|
|
kfree(swl);
|
2005-04-16 16:20:36 -06:00
|
|
|
return (QLA_MEMORY_ALLOC_FAILED);
|
|
|
|
}
|
|
|
|
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
|
|
|
|
/* Set start port ID scan at adapter ID. */
|
|
|
|
first_dev = 1;
|
|
|
|
last_dev = 0;
|
|
|
|
|
|
|
|
/* Starting free loop ID. */
|
2008-11-06 11:40:51 -07:00
|
|
|
loop_id = ha->min_external_loopid;
|
|
|
|
for (; loop_id <= ha->max_loop_id; loop_id++) {
|
|
|
|
if (qla2x00_is_reserved_id(vha, loop_id))
|
2005-04-16 16:20:36 -06:00
|
|
|
continue;
|
|
|
|
|
2010-02-18 11:07:27 -07:00
|
|
|
if (atomic_read(&vha->loop_down_timer) ||
|
|
|
|
LOOP_TRANSITION(vha)) {
|
|
|
|
atomic_set(&vha->loop_down_timer, 0);
|
|
|
|
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
|
|
|
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
2010-02-18 11:07:27 -07:00
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (swl != NULL) {
|
|
|
|
if (last_dev) {
|
|
|
|
wrap.b24 = new_fcport->d_id.b24;
|
|
|
|
} else {
|
|
|
|
new_fcport->d_id.b24 = swl[swl_idx].d_id.b24;
|
|
|
|
memcpy(new_fcport->node_name,
|
|
|
|
swl[swl_idx].node_name, WWN_SIZE);
|
|
|
|
memcpy(new_fcport->port_name,
|
|
|
|
swl[swl_idx].port_name, WWN_SIZE);
|
2006-10-02 13:00:43 -06:00
|
|
|
memcpy(new_fcport->fabric_port_name,
|
|
|
|
swl[swl_idx].fabric_port_name, WWN_SIZE);
|
|
|
|
new_fcport->fp_speed = swl[swl_idx].fp_speed;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
|
|
|
|
last_dev = 1;
|
|
|
|
}
|
|
|
|
swl_idx++;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* Send GA_NXT to the switch */
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_ga_nxt(vha, new_fcport);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"SNS scan failed -- assuming zero-entry "
|
|
|
|
"result...\n");
|
|
|
|
list_for_each_entry_safe(fcport, fcptemp,
|
|
|
|
new_fcports, list) {
|
|
|
|
list_del(&fcport->list);
|
|
|
|
kfree(fcport);
|
|
|
|
}
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If wrap on switch device list, exit. */
|
|
|
|
if (first_dev) {
|
|
|
|
wrap.b24 = new_fcport->d_id.b24;
|
|
|
|
first_dev = 0;
|
|
|
|
} else if (new_fcport->d_id.b24 == wrap.b24) {
|
|
|
|
DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, new_fcport->d_id.b.domain,
|
2005-04-16 16:20:36 -06:00
|
|
|
new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-07-05 14:16:51 -06:00
|
|
|
/* Bypass if same physical adapter. */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (new_fcport->d_id.b24 == base_vha->d_id.b24)
|
2005-04-16 16:20:36 -06:00
|
|
|
continue;
|
|
|
|
|
2007-07-05 14:16:51 -06:00
|
|
|
/* Bypass virtual ports of the same host. */
|
2008-11-06 11:40:51 -07:00
|
|
|
found = 0;
|
|
|
|
if (ha->num_vhosts) {
|
2009-03-05 12:07:02 -07:00
|
|
|
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
|
2008-11-06 11:40:51 -07:00
|
|
|
if (new_fcport->d_id.b24 == vp->d_id.b24) {
|
|
|
|
found = 1;
|
2007-07-05 14:16:51 -06:00
|
|
|
break;
|
2008-11-06 11:40:51 -07:00
|
|
|
}
|
2007-07-05 14:16:51 -06:00
|
|
|
}
|
2008-11-06 11:40:51 -07:00
|
|
|
if (found)
|
2007-07-05 14:16:51 -06:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2005-08-26 20:08:40 -06:00
|
|
|
/* Bypass if same domain and area of adapter. */
|
|
|
|
if (((new_fcport->d_id.b24 & 0xffff00) ==
|
2008-11-06 11:40:51 -07:00
|
|
|
(vha->d_id.b24 & 0xffff00)) && ha->current_topology ==
|
2005-08-26 20:08:40 -06:00
|
|
|
ISP_CFG_FL)
|
|
|
|
continue;
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Bypass reserved domain fields. */
|
|
|
|
if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Locate matching device in database. */
|
|
|
|
found = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
list_for_each_entry(fcport, &vha->vp_fcports, list) {
|
2005-04-16 16:20:36 -06:00
|
|
|
if (memcmp(new_fcport->port_name, fcport->port_name,
|
|
|
|
WWN_SIZE))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
found++;
|
|
|
|
|
2006-10-02 13:00:43 -06:00
|
|
|
/* Update port state. */
|
|
|
|
memcpy(fcport->fabric_port_name,
|
|
|
|
new_fcport->fabric_port_name, WWN_SIZE);
|
|
|
|
fcport->fp_speed = new_fcport->fp_speed;
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/*
|
|
|
|
* If address the same and state FCS_ONLINE, nothing
|
|
|
|
* changed.
|
|
|
|
*/
|
|
|
|
if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
|
|
|
|
atomic_read(&fcport->state) == FCS_ONLINE) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If device was not a fabric device before.
|
|
|
|
*/
|
|
|
|
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
|
|
|
|
fcport->d_id.b24 = new_fcport->d_id.b24;
|
|
|
|
fcport->loop_id = FC_NO_LOOP_ID;
|
|
|
|
fcport->flags |= (FCF_FABRIC_DEVICE |
|
|
|
|
FCF_LOGIN_NEEDED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Port ID changed or device was marked to be updated;
|
|
|
|
* Log it out if still logged in and mark it for
|
|
|
|
* relogin later.
|
|
|
|
*/
|
|
|
|
fcport->d_id.b24 = new_fcport->d_id.b24;
|
|
|
|
fcport->flags |= FCF_LOGIN_NEEDED;
|
|
|
|
if (fcport->loop_id != FC_NO_LOOP_ID &&
|
2010-01-12 13:59:48 -07:00
|
|
|
(fcport->flags & FCF_FCP2_DEVICE) == 0 &&
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->port_type != FCT_INITIATOR &&
|
|
|
|
fcport->port_type != FCT_BROADCAST) {
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->fabric_logout(vha, fcport->loop_id,
|
2005-07-06 11:30:57 -06:00
|
|
|
fcport->d_id.b.domain, fcport->d_id.b.area,
|
|
|
|
fcport->d_id.b.al_pa);
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->loop_id = FC_NO_LOOP_ID;
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
continue;
|
|
|
|
/* If device was not in our fcports list, then add it. */
|
|
|
|
list_add_tail(&new_fcport->list, new_fcports);
|
|
|
|
|
|
|
|
/* Allocate a new replacement fcport. */
|
|
|
|
nxt_d_id.b24 = new_fcport->d_id.b24;
|
2008-11-06 11:40:51 -07:00
|
|
|
new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (new_fcport == NULL) {
|
2005-11-07 02:01:26 -07:00
|
|
|
kfree(swl);
|
2005-04-16 16:20:36 -06:00
|
|
|
return (QLA_MEMORY_ALLOC_FAILED);
|
|
|
|
}
|
|
|
|
new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
|
|
|
|
new_fcport->d_id.b24 = nxt_d_id.b24;
|
|
|
|
}
|
|
|
|
|
2005-11-07 02:01:26 -07:00
|
|
|
kfree(swl);
|
|
|
|
kfree(new_fcport);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_find_new_loop_id
|
|
|
|
* Scan through our port list and find a new usable loop ID.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha: adapter state pointer.
|
|
|
|
* dev: port structure pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* qla2x00 local function return status code.
|
|
|
|
*
|
|
|
|
* Context:
|
|
|
|
* Kernel context.
|
|
|
|
*/
|
2006-06-30 03:33:06 -06:00
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
int found;
|
|
|
|
fc_port_t *fcport;
|
|
|
|
uint16_t first_loop_id;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
struct scsi_qla_host *vp;
|
2009-03-05 12:07:02 -07:00
|
|
|
struct scsi_qla_host *tvp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
|
|
|
|
/* Save starting loop ID. */
|
|
|
|
first_loop_id = dev->loop_id;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
/* Skip loop ID if already used by adapter. */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (dev->loop_id == vha->loop_id)
|
2005-04-16 16:20:36 -06:00
|
|
|
dev->loop_id++;
|
|
|
|
|
|
|
|
/* Skip reserved loop IDs. */
|
2008-11-06 11:40:51 -07:00
|
|
|
while (qla2x00_is_reserved_id(vha, dev->loop_id))
|
2005-04-16 16:20:36 -06:00
|
|
|
dev->loop_id++;
|
|
|
|
|
|
|
|
/* Reset loop ID if passed the end. */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (dev->loop_id > ha->max_loop_id) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/* first loop ID. */
|
|
|
|
dev->loop_id = ha->min_external_loopid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for loop ID being already in use. */
|
|
|
|
found = 0;
|
|
|
|
fcport = NULL;
|
2009-03-05 12:07:02 -07:00
|
|
|
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
|
2008-11-06 11:40:51 -07:00
|
|
|
list_for_each_entry(fcport, &vp->vp_fcports, list) {
|
|
|
|
if (fcport->loop_id == dev->loop_id &&
|
|
|
|
fcport != dev) {
|
|
|
|
/* ID possibly in use */
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
2008-11-06 11:40:51 -07:00
|
|
|
if (found)
|
|
|
|
break;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If not in use then it is free to use. */
|
|
|
|
if (!found) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ID in use. Try next value. */
|
|
|
|
dev->loop_id++;
|
|
|
|
|
|
|
|
/* If wrap around. No free ID to use. */
|
|
|
|
if (dev->loop_id == first_loop_id) {
|
|
|
|
dev->loop_id = FC_NO_LOOP_ID;
|
|
|
|
rval = QLA_FUNCTION_FAILED;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_device_resync
|
|
|
|
* Marks devices in the database that needs resynchronization.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Context:
|
|
|
|
* Kernel context.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_device_resync(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
uint32_t mask;
|
|
|
|
fc_port_t *fcport;
|
|
|
|
uint32_t rscn_entry;
|
|
|
|
uint8_t rscn_out_iter;
|
|
|
|
uint8_t format;
|
2010-05-04 16:01:31 -06:00
|
|
|
port_id_t d_id = {};
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
rval = QLA_RSCNS_HANDLED;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
while (vha->rscn_out_ptr != vha->rscn_in_ptr ||
|
|
|
|
vha->flags.rscn_queue_overflow) {
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rscn_entry = vha->rscn_queue[vha->rscn_out_ptr];
|
2005-04-16 16:20:36 -06:00
|
|
|
format = MSB(MSW(rscn_entry));
|
|
|
|
d_id.b.domain = LSB(MSW(rscn_entry));
|
|
|
|
d_id.b.area = MSB(LSW(rscn_entry));
|
|
|
|
d_id.b.al_pa = LSB(LSW(rscn_entry));
|
|
|
|
|
|
|
|
DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = "
|
|
|
|
"[%02x/%02x%02x%02x].\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, vha->rscn_out_ptr, format, d_id.b.domain,
|
2005-04-16 16:20:36 -06:00
|
|
|
d_id.b.area, d_id.b.al_pa));
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->rscn_out_ptr++;
|
|
|
|
if (vha->rscn_out_ptr == MAX_RSCN_COUNT)
|
|
|
|
vha->rscn_out_ptr = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Skip duplicate entries. */
|
2008-11-06 11:40:51 -07:00
|
|
|
for (rscn_out_iter = vha->rscn_out_ptr;
|
|
|
|
!vha->flags.rscn_queue_overflow &&
|
|
|
|
rscn_out_iter != vha->rscn_in_ptr;
|
2005-04-16 16:20:36 -06:00
|
|
|
rscn_out_iter = (rscn_out_iter ==
|
|
|
|
(MAX_RSCN_COUNT - 1)) ? 0: rscn_out_iter + 1) {
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (rscn_entry != vha->rscn_queue[rscn_out_iter])
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
|
|
|
|
DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue "
|
2008-11-06 11:40:51 -07:00
|
|
|
"entry found at [%d].\n", vha->host_no,
|
2005-04-16 16:20:36 -06:00
|
|
|
rscn_out_iter));
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->rscn_out_ptr = rscn_out_iter;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Queue overflow, set switch default case. */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (vha->flags.rscn_queue_overflow) {
|
2005-04-16 16:20:36 -06:00
|
|
|
DEBUG(printk("scsi(%ld): device_resync: rscn "
|
2008-11-06 11:40:51 -07:00
|
|
|
"overflow.\n", vha->host_no));
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
format = 3;
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.rscn_queue_overflow = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (format) {
|
|
|
|
case 0:
|
|
|
|
mask = 0xffffff;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
mask = 0xffff00;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
mask = 0xff0000;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mask = 0x0;
|
|
|
|
d_id.b24 = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->rscn_out_ptr = vha->rscn_in_ptr;
|
2005-04-16 16:20:36 -06:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
list_for_each_entry(fcport, &vha->vp_fcports, list) {
|
2005-04-16 16:20:36 -06:00
|
|
|
if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
|
|
|
|
(fcport->d_id.b24 & mask) != d_id.b24 ||
|
|
|
|
fcport->port_type == FCT_BROADCAST)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (atomic_read(&fcport->state) == FCS_ONLINE) {
|
|
|
|
if (format != 3 ||
|
|
|
|
fcport->port_type != FCT_INITIATOR) {
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_mark_device_lost(vha, fcport,
|
2006-01-20 15:53:13 -07:00
|
|
|
0, 0);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_fabric_dev_login
|
|
|
|
* Login fabric target device and update FC port database.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha: adapter state pointer.
|
|
|
|
* fcport: port structure list pointer.
|
|
|
|
* next_loopid: contains value of a new loop ID that can be used
|
|
|
|
* by the next login attempt.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* qla2x00 local function return status code.
|
|
|
|
*
|
|
|
|
* Context:
|
|
|
|
* Kernel context.
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport,
|
2005-04-16 16:20:36 -06:00
|
|
|
uint16_t *next_loopid)
|
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
int retry;
|
2005-07-06 11:31:37 -06:00
|
|
|
uint8_t opts;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
retry = 0;
|
|
|
|
|
2009-08-20 12:06:05 -06:00
|
|
|
if (IS_ALOGIO_CAPABLE(ha)) {
|
2010-05-04 16:01:26 -06:00
|
|
|
if (fcport->flags & FCF_ASYNC_SENT)
|
|
|
|
return rval;
|
|
|
|
fcport->flags |= FCF_ASYNC_SENT;
|
2009-08-20 12:06:05 -06:00
|
|
|
rval = qla2x00_post_async_login_work(vha, fcport, NULL);
|
|
|
|
if (!rval)
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
2010-05-04 16:01:26 -06:00
|
|
|
fcport->flags &= ~FCF_ASYNC_SENT;
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_fabric_login(vha, fcport, next_loopid);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval == QLA_SUCCESS) {
|
2010-01-12 13:59:48 -07:00
|
|
|
/* Send an ADISC to FCP2 devices.*/
|
2005-07-06 11:31:37 -06:00
|
|
|
opts = 0;
|
2010-01-12 13:59:48 -07:00
|
|
|
if (fcport->flags & FCF_FCP2_DEVICE)
|
2005-07-06 11:31:37 -06:00
|
|
|
opts |= BIT_1;
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_get_port_database(vha, fcport, opts);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->fabric_logout(vha, fcport->loop_id,
|
2005-07-06 11:30:57 -06:00
|
|
|
fcport->d_id.b.domain, fcport->d_id.b.area,
|
|
|
|
fcport->d_id.b.al_pa);
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_mark_device_lost(vha, fcport, 1, 0);
|
2005-04-16 16:20:36 -06:00
|
|
|
} else {
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_update_fcport(vha, fcport);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_fabric_login
|
|
|
|
* Issue fabric login command.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
* device = pointer to FC device type structure.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 - Login successfully
|
|
|
|
* 1 - Login failed
|
|
|
|
* 2 - Initiator device
|
|
|
|
* 3 - Fatal error
|
|
|
|
*/
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport,
|
2005-04-16 16:20:36 -06:00
|
|
|
uint16_t *next_loopid)
|
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
int retry;
|
|
|
|
uint16_t tmp_loopid;
|
|
|
|
uint16_t mb[MAILBOX_REGISTER_COUNT];
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
retry = 0;
|
|
|
|
tmp_loopid = 0;
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x "
|
|
|
|
"for port %02x%02x%02x.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, fcport->loop_id, fcport->d_id.b.domain,
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->d_id.b.area, fcport->d_id.b.al_pa));
|
|
|
|
|
|
|
|
/* Login fcport on switch. */
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->fabric_login(vha, fcport->loop_id,
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->d_id.b.domain, fcport->d_id.b.area,
|
|
|
|
fcport->d_id.b.al_pa, mb, BIT_0);
|
|
|
|
if (mb[0] == MBS_PORT_ID_USED) {
|
|
|
|
/*
|
|
|
|
* Device has another loop ID. The firmware team
|
2005-07-06 11:31:37 -06:00
|
|
|
* recommends the driver perform an implicit login with
|
|
|
|
* the specified ID again. The ID we just used is save
|
|
|
|
* here so we return with an ID that can be tried by
|
|
|
|
* the next login.
|
2005-04-16 16:20:36 -06:00
|
|
|
*/
|
|
|
|
retry++;
|
|
|
|
tmp_loopid = fcport->loop_id;
|
|
|
|
fcport->loop_id = mb[1];
|
|
|
|
|
|
|
|
DEBUG(printk("Fabric Login: port in use - next "
|
|
|
|
"loop id=0x%04x, port Id=%02x%02x%02x.\n",
|
|
|
|
fcport->loop_id, fcport->d_id.b.domain,
|
|
|
|
fcport->d_id.b.area, fcport->d_id.b.al_pa));
|
|
|
|
|
|
|
|
} else if (mb[0] == MBS_COMMAND_COMPLETE) {
|
|
|
|
/*
|
|
|
|
* Login succeeded.
|
|
|
|
*/
|
|
|
|
if (retry) {
|
|
|
|
/* A retry occurred before. */
|
|
|
|
*next_loopid = tmp_loopid;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* No retry occurred before. Just increment the
|
|
|
|
* ID value for next login.
|
|
|
|
*/
|
|
|
|
*next_loopid = (fcport->loop_id + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mb[1] & BIT_0) {
|
|
|
|
fcport->port_type = FCT_INITIATOR;
|
|
|
|
} else {
|
|
|
|
fcport->port_type = FCT_TARGET;
|
|
|
|
if (mb[1] & BIT_1) {
|
2009-08-25 12:36:16 -06:00
|
|
|
fcport->flags |= FCF_FCP2_DEVICE;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-26 20:08:10 -06:00
|
|
|
if (mb[10] & BIT_0)
|
|
|
|
fcport->supported_classes |= FC_COS_CLASS2;
|
|
|
|
if (mb[10] & BIT_1)
|
|
|
|
fcport->supported_classes |= FC_COS_CLASS3;
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
break;
|
|
|
|
} else if (mb[0] == MBS_LOOP_ID_USED) {
|
|
|
|
/*
|
|
|
|
* Loop ID already used, try next loop ID.
|
|
|
|
*/
|
|
|
|
fcport->loop_id++;
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_find_new_loop_id(vha, fcport);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval != QLA_SUCCESS) {
|
|
|
|
/* Ran out of loop IDs to use */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (mb[0] == MBS_COMMAND_ERROR) {
|
|
|
|
/*
|
|
|
|
* Firmware possibly timed out during login. If NO
|
|
|
|
* retries are left to do then the device is declared
|
|
|
|
* dead.
|
|
|
|
*/
|
|
|
|
*next_loopid = fcport->loop_id;
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->fabric_logout(vha, fcport->loop_id,
|
2005-07-06 11:30:57 -06:00
|
|
|
fcport->d_id.b.domain, fcport->d_id.b.area,
|
|
|
|
fcport->d_id.b.al_pa);
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_mark_device_lost(vha, fcport, 1, 0);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
rval = 1;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* unrecoverable / not handled error
|
|
|
|
*/
|
|
|
|
DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x "
|
2005-07-06 11:32:07 -06:00
|
|
|
"loop_id=%x jiffies=%lx.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
__func__, vha->host_no, mb[0],
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->d_id.b.domain, fcport->d_id.b.area,
|
|
|
|
fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
|
|
|
|
|
|
|
|
*next_loopid = fcport->loop_id;
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->fabric_logout(vha, fcport->loop_id,
|
2005-07-06 11:30:57 -06:00
|
|
|
fcport->d_id.b.domain, fcport->d_id.b.area,
|
|
|
|
fcport->d_id.b.al_pa);
|
2005-04-16 16:20:36 -06:00
|
|
|
fcport->loop_id = FC_NO_LOOP_ID;
|
2005-10-27 12:09:38 -06:00
|
|
|
fcport->login_retry = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
rval = 3;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_local_device_login
|
|
|
|
* Issue local device login command.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
* loop_id = loop id of device to login to.
|
|
|
|
*
|
|
|
|
* Returns (Where's the #define!!!!):
|
|
|
|
* 0 - Login successfully
|
|
|
|
* 1 - Login failed
|
|
|
|
* 3 - Fatal error
|
|
|
|
*/
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_local_device_login(scsi_qla_host_t *vha, fc_port_t *fcport)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
uint16_t mb[MAILBOX_REGISTER_COUNT];
|
|
|
|
|
|
|
|
memset(mb, 0, sizeof(mb));
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_login_local_device(vha, fcport, mb, BIT_0);
|
2005-04-16 16:20:36 -06:00
|
|
|
if (rval == QLA_SUCCESS) {
|
|
|
|
/* Interrogate mailbox registers for any errors */
|
|
|
|
if (mb[0] == MBS_COMMAND_ERROR)
|
|
|
|
rval = 1;
|
|
|
|
else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR)
|
|
|
|
/* device not in PCB table */
|
|
|
|
rval = 3;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_loop_resync
|
|
|
|
* Resync with fibre channel devices.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success
|
|
|
|
*/
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_loop_resync(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2008-12-09 17:45:39 -07:00
|
|
|
int rval = QLA_SUCCESS;
|
2005-04-16 16:20:36 -06:00
|
|
|
uint32_t wait_time;
|
2009-04-06 23:33:42 -06:00
|
|
|
struct req_que *req;
|
|
|
|
struct rsp_que *rsp;
|
|
|
|
|
2009-08-05 10:18:40 -06:00
|
|
|
if (vha->hw->flags.cpu_affinity_enabled)
|
2009-04-06 23:33:42 -06:00
|
|
|
req = vha->hw->req_q_map[0];
|
|
|
|
else
|
|
|
|
req = vha->req;
|
|
|
|
rsp = req->rsp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
atomic_set(&vha->loop_state, LOOP_UPDATE);
|
|
|
|
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
|
|
|
|
if (vha->flags.online) {
|
|
|
|
if (!(rval = qla2x00_fw_ready(vha))) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Wait at most MAX_TARGET RSCNs for a stable link. */
|
|
|
|
wait_time = 256;
|
|
|
|
do {
|
2008-11-06 11:40:51 -07:00
|
|
|
atomic_set(&vha->loop_state, LOOP_UPDATE);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
/* Issue a marker after FW becomes ready. */
|
2008-12-09 17:45:39 -07:00
|
|
|
qla2x00_marker(vha, req, rsp, 0, 0,
|
|
|
|
MK_SYNC_ALL);
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->marker_needed = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* Remap devices on Loop. */
|
2008-11-06 11:40:51 -07:00
|
|
|
clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_configure_loop(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
wait_time--;
|
2008-11-06 11:40:51 -07:00
|
|
|
} while (!atomic_read(&vha->loop_down_timer) &&
|
|
|
|
!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
|
|
|
|
&& wait_time && (test_bit(LOOP_RESYNC_NEEDED,
|
|
|
|
&vha->dpc_flags)));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
|
2005-04-16 16:20:36 -06:00
|
|
|
return (QLA_FUNCTION_FAILED);
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (rval)
|
2005-04-16 16:20:36 -06:00
|
|
|
DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
|
|
|
|
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
2006-01-20 15:53:13 -07:00
|
|
|
void
|
2009-08-25 12:36:20 -06:00
|
|
|
qla2x00_update_fcports(scsi_qla_host_t *base_vha)
|
2006-01-20 15:53:13 -07:00
|
|
|
{
|
|
|
|
fc_port_t *fcport;
|
2009-08-25 12:36:20 -06:00
|
|
|
struct scsi_qla_host *tvp, *vha;
|
2006-01-20 15:53:13 -07:00
|
|
|
|
|
|
|
/* Go with deferred removal of rport references. */
|
2009-08-25 12:36:20 -06:00
|
|
|
list_for_each_entry_safe(vha, tvp, &base_vha->hw->vp_list, list)
|
|
|
|
list_for_each_entry(fcport, &vha->vp_fcports, list)
|
|
|
|
if (fcport && fcport->drport &&
|
|
|
|
atomic_read(&fcport->state) != FCS_UNCONFIGURED)
|
|
|
|
qla2x00_rport_del(fcport);
|
2006-01-20 15:53:13 -07:00
|
|
|
}
|
|
|
|
|
2010-04-12 18:59:55 -06:00
|
|
|
void
|
|
|
|
qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
|
|
|
|
{
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev);
|
|
|
|
struct scsi_qla_host *tvp;
|
|
|
|
|
|
|
|
vha->flags.online = 0;
|
|
|
|
ha->flags.chip_reset_done = 0;
|
|
|
|
clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
|
|
|
|
ha->qla_stats.total_isp_aborts++;
|
|
|
|
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"Performing ISP error recovery - ha= %p.\n", ha);
|
|
|
|
|
|
|
|
/* Chip reset does not apply to 82XX */
|
|
|
|
if (!IS_QLA82XX(ha))
|
|
|
|
ha->isp_ops->reset_chip(vha);
|
|
|
|
|
|
|
|
atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
|
|
|
|
if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
|
|
|
|
atomic_set(&vha->loop_state, LOOP_DOWN);
|
|
|
|
qla2x00_mark_all_devices_lost(vha, 0);
|
|
|
|
list_for_each_entry_safe(vp, tvp, &base_vha->hw->vp_list, list)
|
|
|
|
qla2x00_mark_all_devices_lost(vp, 0);
|
|
|
|
} else {
|
|
|
|
if (!atomic_read(&vha->loop_down_timer))
|
|
|
|
atomic_set(&vha->loop_down_timer,
|
|
|
|
LOOP_DOWN_TIME);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure for ISP 82XX IO DMA is complete */
|
|
|
|
if (IS_QLA82XX(ha))
|
|
|
|
qla82xx_wait_for_pending_commands(vha);
|
|
|
|
|
|
|
|
/* Requeue all commands in outstanding command list. */
|
|
|
|
qla2x00_abort_all_cmds(vha, DID_RESET << 16);
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/*
|
|
|
|
* qla2x00_abort_isp
|
|
|
|
* Resets ISP and aborts all outstanding commands.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success
|
|
|
|
*/
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_abort_isp(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2006-08-23 15:54:55 -06:00
|
|
|
int rval;
|
2005-04-16 16:20:36 -06:00
|
|
|
uint8_t status = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
struct scsi_qla_host *vp;
|
2009-03-05 12:07:02 -07:00
|
|
|
struct scsi_qla_host *tvp;
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (vha->flags.online) {
|
2010-04-12 18:59:55 -06:00
|
|
|
qla2x00_abort_isp_cleanup(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2009-12-15 22:29:46 -07:00
|
|
|
if (unlikely(pci_channel_offline(ha->pdev) &&
|
|
|
|
ha->flags.pci_channel_io_perm_failure)) {
|
|
|
|
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
|
|
|
|
status = 0;
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
ha->isp_ops->get_flash_version(vha, req->ring);
|
2007-01-29 11:22:21 -07:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->nvram_config(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (!qla2x00_restart_isp(vha)) {
|
|
|
|
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (!atomic_read(&vha->loop_down_timer)) {
|
2005-04-16 16:20:36 -06:00
|
|
|
/*
|
|
|
|
* Issue marker command only when we are going
|
|
|
|
* to start the I/O .
|
|
|
|
*/
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->marker_needed = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.online = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2007-07-19 16:06:00 -06:00
|
|
|
ha->isp_ops->enable_intrs(ha);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2005-07-06 11:32:07 -06:00
|
|
|
ha->isp_abort_cnt = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
|
2006-08-23 15:54:55 -06:00
|
|
|
|
2009-10-13 16:16:47 -06:00
|
|
|
if (IS_QLA81XX(ha))
|
|
|
|
qla2x00_get_fw_version(vha,
|
|
|
|
&ha->fw_major_version,
|
|
|
|
&ha->fw_minor_version,
|
|
|
|
&ha->fw_subminor_version,
|
|
|
|
&ha->fw_attributes, &ha->fw_memory_size,
|
|
|
|
ha->mpi_version, &ha->mpi_capabilities,
|
|
|
|
ha->phy_version);
|
|
|
|
|
2008-01-17 10:02:17 -07:00
|
|
|
if (ha->fce) {
|
|
|
|
ha->flags.fce_enabled = 1;
|
|
|
|
memset(ha->fce, 0,
|
|
|
|
fce_calc_size(ha->fce_bufs));
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_enable_fce_trace(vha,
|
2008-01-17 10:02:17 -07:00
|
|
|
ha->fce_dma, ha->fce_bufs, ha->fce_mb,
|
|
|
|
&ha->fce_bufs);
|
|
|
|
if (rval) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to reinitialize FCE "
|
|
|
|
"(%d).\n", rval);
|
|
|
|
ha->flags.fce_enabled = 0;
|
|
|
|
}
|
|
|
|
}
|
2008-07-10 17:55:54 -06:00
|
|
|
|
|
|
|
if (ha->eft) {
|
|
|
|
memset(ha->eft, 0, EFT_SIZE);
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_enable_eft_trace(vha,
|
2008-07-10 17:55:54 -06:00
|
|
|
ha->eft_dma, EFT_NUM_BUFFERS);
|
|
|
|
if (rval) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to reinitialize EFT "
|
|
|
|
"(%d).\n", rval);
|
|
|
|
}
|
|
|
|
}
|
2005-04-16 16:20:36 -06:00
|
|
|
} else { /* failed the ISP abort */
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.online = 1;
|
|
|
|
if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
|
2005-04-16 16:20:36 -06:00
|
|
|
if (ha->isp_abort_cnt == 0) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"ISP error recovery failed - "
|
|
|
|
"board disabled\n");
|
2005-07-06 11:32:07 -06:00
|
|
|
/*
|
2005-04-16 16:20:36 -06:00
|
|
|
* The next call disables the board
|
|
|
|
* completely.
|
|
|
|
*/
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->reset_adapter(vha);
|
|
|
|
vha->flags.online = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
clear_bit(ISP_ABORT_RETRY,
|
2008-11-06 11:40:51 -07:00
|
|
|
&vha->dpc_flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
status = 0;
|
|
|
|
} else { /* schedule another ISP abort */
|
|
|
|
ha->isp_abort_cnt--;
|
|
|
|
DEBUG(printk("qla%ld: ISP abort - "
|
2005-07-06 11:31:37 -06:00
|
|
|
"retry remaining %d\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, ha->isp_abort_cnt));
|
2005-04-16 16:20:36 -06:00
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
|
|
|
|
DEBUG(printk("qla2x00(%ld): ISP error recovery "
|
|
|
|
"- retrying (%d) more times\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, ha->isp_abort_cnt));
|
|
|
|
set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
|
2005-04-16 16:20:36 -06:00
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
}
|
2005-07-06 11:32:07 -06:00
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (!status) {
|
|
|
|
DEBUG(printk(KERN_INFO
|
|
|
|
"qla2x00_abort_isp(%ld): succeeded.\n",
|
|
|
|
vha->host_no));
|
2009-03-05 12:07:02 -07:00
|
|
|
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
|
2008-11-06 11:40:51 -07:00
|
|
|
if (vp->vp_idx)
|
|
|
|
qla2x00_vp_abort_isp(vp);
|
|
|
|
}
|
|
|
|
} else {
|
2005-04-16 16:20:36 -06:00
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"qla2x00_abort_isp: **** FAILED ****\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return(status);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla2x00_restart_isp
|
|
|
|
* restarts the ISP after a reset
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
* 0 = success
|
|
|
|
*/
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_restart_isp(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
2009-03-05 12:07:03 -07:00
|
|
|
int status = 0;
|
2005-04-16 16:20:36 -06:00
|
|
|
uint32_t wait_time;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
|
|
|
struct rsp_que *rsp = ha->rsp_q_map[0];
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
/* If firmware needs to be loaded */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (qla2x00_isp_firmware(vha)) {
|
|
|
|
vha->flags.online = 0;
|
|
|
|
status = ha->isp_ops->chip_diag(vha);
|
|
|
|
if (!status)
|
|
|
|
status = qla2x00_setup_chip(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (!status && !(status = qla2x00_init_rings(vha))) {
|
|
|
|
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
2009-03-24 10:08:07 -06:00
|
|
|
ha->flags.chip_reset_done = 1;
|
2008-12-09 17:45:39 -07:00
|
|
|
/* Initialize the queues in use */
|
|
|
|
qla25xx_init_queues(ha);
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
status = qla2x00_fw_ready(vha);
|
|
|
|
if (!status) {
|
2005-04-16 16:20:36 -06:00
|
|
|
DEBUG(printk("%s(): Start configure loop, "
|
2006-06-23 17:11:05 -06:00
|
|
|
"status = %d\n", __func__, status));
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
/* Issue a marker after FW becomes ready. */
|
2008-12-09 17:45:39 -07:00
|
|
|
qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.online = 1;
|
2005-04-16 16:20:36 -06:00
|
|
|
/* Wait at most MAX_TARGET RSCNs for a stable link. */
|
|
|
|
wait_time = 256;
|
|
|
|
do {
|
2008-11-06 11:40:51 -07:00
|
|
|
clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
|
|
|
qla2x00_configure_loop(vha);
|
2005-04-16 16:20:36 -06:00
|
|
|
wait_time--;
|
2008-11-06 11:40:51 -07:00
|
|
|
} while (!atomic_read(&vha->loop_down_timer) &&
|
|
|
|
!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags))
|
|
|
|
&& wait_time && (test_bit(LOOP_RESYNC_NEEDED,
|
|
|
|
&vha->dpc_flags)));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* if no cable then assume it's good */
|
2008-11-06 11:40:51 -07:00
|
|
|
if ((vha->device_flags & DFLG_NO_CABLE))
|
2005-04-16 16:20:36 -06:00
|
|
|
status = 0;
|
|
|
|
|
|
|
|
DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
|
|
|
|
__func__,
|
2006-06-23 17:11:05 -06:00
|
|
|
status));
|
2005-04-16 16:20:36 -06:00
|
|
|
}
|
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
static int
|
|
|
|
qla25xx_init_queues(struct qla_hw_data *ha)
|
|
|
|
{
|
|
|
|
struct rsp_que *rsp = NULL;
|
|
|
|
struct req_que *req = NULL;
|
|
|
|
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
|
|
|
|
int ret = -1;
|
|
|
|
int i;
|
|
|
|
|
2009-04-06 23:33:40 -06:00
|
|
|
for (i = 1; i < ha->max_rsp_queues; i++) {
|
2008-12-09 17:45:39 -07:00
|
|
|
rsp = ha->rsp_q_map[i];
|
|
|
|
if (rsp) {
|
|
|
|
rsp->options &= ~BIT_0;
|
2009-02-08 21:50:11 -07:00
|
|
|
ret = qla25xx_init_rsp_que(base_vha, rsp);
|
2008-12-09 17:45:39 -07:00
|
|
|
if (ret != QLA_SUCCESS)
|
|
|
|
DEBUG2_17(printk(KERN_WARNING
|
|
|
|
"%s Rsp que:%d init failed\n", __func__,
|
|
|
|
rsp->id));
|
|
|
|
else
|
|
|
|
DEBUG2_17(printk(KERN_INFO
|
|
|
|
"%s Rsp que:%d inited\n", __func__,
|
|
|
|
rsp->id));
|
|
|
|
}
|
2009-04-06 23:33:40 -06:00
|
|
|
}
|
|
|
|
for (i = 1; i < ha->max_req_queues; i++) {
|
2008-12-09 17:45:39 -07:00
|
|
|
req = ha->req_q_map[i];
|
|
|
|
if (req) {
|
2009-01-08 16:41:08 -07:00
|
|
|
/* Clear outstanding commands array. */
|
2008-12-09 17:45:39 -07:00
|
|
|
req->options &= ~BIT_0;
|
2009-02-08 21:50:11 -07:00
|
|
|
ret = qla25xx_init_req_que(base_vha, req);
|
2008-12-09 17:45:39 -07:00
|
|
|
if (ret != QLA_SUCCESS)
|
|
|
|
DEBUG2_17(printk(KERN_WARNING
|
|
|
|
"%s Req que:%d init failed\n", __func__,
|
|
|
|
req->id));
|
|
|
|
else
|
|
|
|
DEBUG2_17(printk(KERN_WARNING
|
2009-01-08 16:41:08 -07:00
|
|
|
"%s Req que:%d inited\n", __func__,
|
2008-12-09 17:45:39 -07:00
|
|
|
req->id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2005-04-16 16:20:36 -06:00
|
|
|
/*
|
|
|
|
* qla2x00_reset_adapter
|
|
|
|
* Reset adapter.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*/
|
2005-07-06 11:30:05 -06:00
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_reset_adapter(scsi_qla_host_t *vha)
|
2005-04-16 16:20:36 -06:00
|
|
|
{
|
|
|
|
unsigned long flags = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:30:26 -06:00
|
|
|
struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
|
2005-04-16 16:20:36 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.online = 0;
|
2007-07-19 16:06:00 -06:00
|
|
|
ha->isp_ops->disable_intrs(ha);
|
2005-04-16 16:20:36 -06:00
|
|
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RESET_RISC);
|
|
|
|
RD_REG_WORD(®->hccr); /* PCI Posting. */
|
|
|
|
WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC);
|
|
|
|
RD_REG_WORD(®->hccr); /* PCI Posting. */
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
|
|
|
}
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_reset_adapter(scsi_qla_host_t *vha)
|
2005-07-06 11:31:37 -06:00
|
|
|
{
|
|
|
|
unsigned long flags = 0;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:31:37 -06:00
|
|
|
struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
|
|
|
|
|
2010-04-12 18:59:55 -06:00
|
|
|
if (IS_QLA82XX(ha))
|
|
|
|
return;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.online = 0;
|
2007-07-19 16:06:00 -06:00
|
|
|
ha->isp_ops->disable_intrs(ha);
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
spin_lock_irqsave(&ha->hardware_lock, flags);
|
|
|
|
WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET);
|
|
|
|
RD_REG_DWORD(®->hccr);
|
|
|
|
WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE);
|
|
|
|
RD_REG_DWORD(®->hccr);
|
|
|
|
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
2009-01-22 10:45:30 -07:00
|
|
|
|
|
|
|
if (IS_NOPOLLING_TYPE(ha))
|
|
|
|
ha->isp_ops->enable_intrs(ha);
|
2005-07-06 11:31:37 -06:00
|
|
|
}
|
|
|
|
|
2007-04-16 13:37:43 -06:00
|
|
|
/* On sparc systems, obtain port and node WWN from firmware
|
|
|
|
* properties.
|
|
|
|
*/
|
2008-11-06 11:40:51 -07:00
|
|
|
static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *vha,
|
|
|
|
struct nvram_24xx *nv)
|
2007-04-16 13:37:43 -06:00
|
|
|
{
|
|
|
|
#ifdef CONFIG_SPARC
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2007-04-16 13:37:43 -06:00
|
|
|
struct pci_dev *pdev = ha->pdev;
|
2007-05-08 01:36:49 -06:00
|
|
|
struct device_node *dp = pci_device_to_OF_node(pdev);
|
|
|
|
const u8 *val;
|
2007-04-16 13:37:43 -06:00
|
|
|
int len;
|
|
|
|
|
|
|
|
val = of_get_property(dp, "port-wwn", &len);
|
|
|
|
if (val && len >= WWN_SIZE)
|
|
|
|
memcpy(nv->port_name, val, WWN_SIZE);
|
|
|
|
|
|
|
|
val = of_get_property(dp, "node-wwn", &len);
|
|
|
|
if (val && len >= WWN_SIZE)
|
|
|
|
memcpy(nv->node_name, val, WWN_SIZE);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_nvram_config(scsi_qla_host_t *vha)
|
2005-07-06 11:31:37 -06:00
|
|
|
{
|
2007-04-16 13:37:43 -06:00
|
|
|
int rval;
|
2005-07-06 11:31:37 -06:00
|
|
|
struct init_cb_24xx *icb;
|
|
|
|
struct nvram_24xx *nv;
|
|
|
|
uint32_t *dptr;
|
|
|
|
uint8_t *dptr1, *dptr2;
|
|
|
|
uint32_t chksum;
|
|
|
|
uint16_t cnt;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2007-04-16 13:37:43 -06:00
|
|
|
rval = QLA_SUCCESS;
|
2005-07-06 11:31:37 -06:00
|
|
|
icb = (struct init_cb_24xx *)ha->init_cb;
|
2007-07-26 14:43:34 -06:00
|
|
|
nv = ha->nvram;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
/* Determine NVRAM starting address. */
|
2009-04-06 23:33:50 -06:00
|
|
|
if (ha->flags.port0) {
|
|
|
|
ha->nvram_base = FA_NVRAM_FUNC0_ADDR;
|
|
|
|
ha->vpd_base = FA_NVRAM_VPD0_ADDR;
|
|
|
|
} else {
|
2005-07-06 11:31:37 -06:00
|
|
|
ha->nvram_base = FA_NVRAM_FUNC1_ADDR;
|
2006-03-09 15:27:34 -07:00
|
|
|
ha->vpd_base = FA_NVRAM_VPD1_ADDR;
|
|
|
|
}
|
2009-04-06 23:33:50 -06:00
|
|
|
ha->nvram_size = sizeof(struct nvram_24xx);
|
|
|
|
ha->vpd_size = FA_NVRAM_VPD_SIZE;
|
2010-04-12 18:59:55 -06:00
|
|
|
if (IS_QLA82XX(ha))
|
|
|
|
ha->vpd_size = FA_VPD_SIZE_82XX;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2007-07-26 14:43:34 -06:00
|
|
|
/* Get VPD data into cache */
|
|
|
|
ha->vpd = ha->nvram + VPD_OFFSET;
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd,
|
2007-07-26 14:43:34 -06:00
|
|
|
ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4);
|
|
|
|
|
|
|
|
/* Get NVRAM data into cache and calculate checksum. */
|
2005-07-06 11:31:37 -06:00
|
|
|
dptr = (uint32_t *)nv;
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base,
|
2005-07-06 11:31:37 -06:00
|
|
|
ha->nvram_size);
|
|
|
|
for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
|
|
|
|
chksum += le32_to_cpu(*dptr++);
|
|
|
|
|
2009-04-06 23:33:39 -06:00
|
|
|
DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
|
2007-07-26 14:43:34 -06:00
|
|
|
DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
/* Bad NVRAM data, set defaults parameters. */
|
|
|
|
if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
|
|
|
|
|| nv->id[3] != ' ' ||
|
|
|
|
nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
|
|
|
|
/* Reset NVRAM data. */
|
|
|
|
qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
|
|
|
|
"checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
|
|
|
|
le16_to_cpu(nv->nvram_version));
|
2007-04-16 13:37:43 -06:00
|
|
|
qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
|
|
|
|
"invalid -- WWPN) defaults.\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set default initialization control block.
|
|
|
|
*/
|
|
|
|
memset(nv, 0, ha->nvram_size);
|
|
|
|
nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
|
|
|
|
nv->version = __constant_cpu_to_le16(ICB_VERSION);
|
|
|
|
nv->frame_payload_size = __constant_cpu_to_le16(2048);
|
|
|
|
nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
|
|
|
|
nv->exchange_count = __constant_cpu_to_le16(0);
|
|
|
|
nv->hard_address = __constant_cpu_to_le16(124);
|
|
|
|
nv->port_name[0] = 0x21;
|
2009-04-06 23:33:50 -06:00
|
|
|
nv->port_name[1] = 0x00 + ha->port_no;
|
2007-04-16 13:37:43 -06:00
|
|
|
nv->port_name[2] = 0x00;
|
|
|
|
nv->port_name[3] = 0xe0;
|
|
|
|
nv->port_name[4] = 0x8b;
|
|
|
|
nv->port_name[5] = 0x1c;
|
|
|
|
nv->port_name[6] = 0x55;
|
|
|
|
nv->port_name[7] = 0x86;
|
|
|
|
nv->node_name[0] = 0x20;
|
|
|
|
nv->node_name[1] = 0x00;
|
|
|
|
nv->node_name[2] = 0x00;
|
|
|
|
nv->node_name[3] = 0xe0;
|
|
|
|
nv->node_name[4] = 0x8b;
|
|
|
|
nv->node_name[5] = 0x1c;
|
|
|
|
nv->node_name[6] = 0x55;
|
|
|
|
nv->node_name[7] = 0x86;
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_nvram_wwn_from_ofw(vha, nv);
|
2007-04-16 13:37:43 -06:00
|
|
|
nv->login_retry_count = __constant_cpu_to_le16(8);
|
|
|
|
nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
|
|
|
|
nv->login_timeout = __constant_cpu_to_le16(0);
|
|
|
|
nv->firmware_options_1 =
|
|
|
|
__constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
|
|
|
|
nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
|
|
|
|
nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
|
|
|
|
nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
|
|
|
|
nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
|
|
|
|
nv->efi_parameters = __constant_cpu_to_le32(0);
|
|
|
|
nv->reset_delay = 5;
|
|
|
|
nv->max_luns_per_target = __constant_cpu_to_le16(128);
|
|
|
|
nv->port_down_retry_count = __constant_cpu_to_le16(30);
|
|
|
|
nv->link_down_timeout = __constant_cpu_to_le16(30);
|
|
|
|
|
|
|
|
rval = 1;
|
2005-07-06 11:31:37 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset Initialization control block */
|
2008-11-06 11:40:51 -07:00
|
|
|
memset(icb, 0, ha->init_cb_size);
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
/* Copy 1st segment. */
|
|
|
|
dptr1 = (uint8_t *)icb;
|
|
|
|
dptr2 = (uint8_t *)&nv->version;
|
|
|
|
cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
|
|
|
|
while (cnt--)
|
|
|
|
*dptr1++ = *dptr2++;
|
|
|
|
|
|
|
|
icb->login_retry_count = nv->login_retry_count;
|
2006-06-23 17:11:27 -06:00
|
|
|
icb->link_down_on_nos = nv->link_down_on_nos;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
/* Copy 2nd segment. */
|
|
|
|
dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
|
|
|
|
dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
|
|
|
|
cnt = (uint8_t *)&icb->reserved_3 -
|
|
|
|
(uint8_t *)&icb->interrupt_delay_timer;
|
|
|
|
while (cnt--)
|
|
|
|
*dptr1++ = *dptr2++;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup driver NVRAM options.
|
|
|
|
*/
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
|
2007-01-29 11:22:24 -07:00
|
|
|
"QLA2462");
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2006-05-17 16:09:16 -06:00
|
|
|
/* Use alternate WWN? */
|
|
|
|
if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
|
|
|
|
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
|
|
|
|
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
|
|
|
|
}
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
/* Prepare nodename */
|
2006-05-17 16:09:11 -06:00
|
|
|
if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
|
2005-07-06 11:31:37 -06:00
|
|
|
/*
|
|
|
|
* Firmware will apply the following mask if the nodename was
|
|
|
|
* not provided.
|
|
|
|
*/
|
|
|
|
memcpy(icb->node_name, icb->port_name, WWN_SIZE);
|
|
|
|
icb->node_name[0] &= 0xF0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set host adapter parameters. */
|
|
|
|
ha->flags.disable_risc_code_load = 0;
|
2006-12-13 20:20:30 -07:00
|
|
|
ha->flags.enable_lip_reset = 0;
|
|
|
|
ha->flags.enable_lip_full_login =
|
|
|
|
le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
|
|
|
|
ha->flags.enable_target_reset =
|
|
|
|
le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
|
2005-07-06 11:31:37 -06:00
|
|
|
ha->flags.enable_led_scheme = 0;
|
2006-06-23 17:10:39 -06:00
|
|
|
ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2006-05-17 16:09:11 -06:00
|
|
|
ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
|
|
|
|
(BIT_6 | BIT_5 | BIT_4)) >> 4;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
memcpy(ha->fw_seriallink_options24, nv->seriallink_options,
|
|
|
|
sizeof(ha->fw_seriallink_options24));
|
|
|
|
|
|
|
|
/* save HBA serial number */
|
|
|
|
ha->serial0 = icb->port_name[5];
|
|
|
|
ha->serial1 = icb->port_name[6];
|
|
|
|
ha->serial2 = icb->port_name[7];
|
2008-11-06 11:40:51 -07:00
|
|
|
memcpy(vha->node_name, icb->node_name, WWN_SIZE);
|
|
|
|
memcpy(vha->port_name, icb->port_name, WWN_SIZE);
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2006-01-13 18:05:42 -07:00
|
|
|
icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
ha->retry_count = le16_to_cpu(nv->login_retry_count);
|
|
|
|
|
|
|
|
/* Set minimum login_timeout to 4 seconds. */
|
|
|
|
if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
|
|
|
|
nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
|
|
|
|
if (le16_to_cpu(nv->login_timeout) < 4)
|
|
|
|
nv->login_timeout = __constant_cpu_to_le16(4);
|
|
|
|
ha->login_timeout = le16_to_cpu(nv->login_timeout);
|
2008-04-24 16:21:29 -06:00
|
|
|
icb->login_timeout = nv->login_timeout;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2008-02-28 15:06:11 -07:00
|
|
|
/* Set minimum RATOV to 100 tenths of a second. */
|
|
|
|
ha->r_a_tov = 100;
|
2005-07-06 11:31:37 -06:00
|
|
|
|
|
|
|
ha->loop_reset_delay = nv->reset_delay;
|
|
|
|
|
|
|
|
/* Link Down Timeout = 0:
|
|
|
|
*
|
|
|
|
* When Port Down timer expires we will start returning
|
|
|
|
* I/O's to OS with "DID_NO_CONNECT".
|
|
|
|
*
|
|
|
|
* Link Down Timeout != 0:
|
|
|
|
*
|
|
|
|
* The driver waits for the link to come up after link down
|
|
|
|
* before returning I/Os to OS with "DID_NO_CONNECT".
|
|
|
|
*/
|
|
|
|
if (le16_to_cpu(nv->link_down_timeout) == 0) {
|
|
|
|
ha->loop_down_abort_time =
|
|
|
|
(LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
|
|
|
|
} else {
|
|
|
|
ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
|
|
|
|
ha->loop_down_abort_time =
|
|
|
|
(LOOP_DOWN_TIME - ha->link_down_timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Need enough time to try and get the port back. */
|
|
|
|
ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
|
|
|
|
if (qlport_down_retry)
|
|
|
|
ha->port_down_retry_count = qlport_down_retry;
|
|
|
|
|
|
|
|
/* Set login_retry_count */
|
|
|
|
ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
|
|
|
|
if (ha->port_down_retry_count ==
|
|
|
|
le16_to_cpu(nv->port_down_retry_count) &&
|
|
|
|
ha->port_down_retry_count > 3)
|
|
|
|
ha->login_retry_count = ha->port_down_retry_count;
|
|
|
|
else if (ha->port_down_retry_count > (int)ha->login_retry_count)
|
|
|
|
ha->login_retry_count = ha->port_down_retry_count;
|
|
|
|
if (ql2xloginretrycount)
|
|
|
|
ha->login_retry_count = ql2xloginretrycount;
|
|
|
|
|
2005-10-27 12:09:48 -06:00
|
|
|
/* Enable ZIO. */
|
2008-11-06 11:40:51 -07:00
|
|
|
if (!vha->flags.init_done) {
|
2005-10-27 12:09:48 -06:00
|
|
|
ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
|
|
|
|
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
|
|
|
|
ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
|
|
|
|
le16_to_cpu(icb->interrupt_delay_timer): 2;
|
|
|
|
}
|
|
|
|
icb->firmware_options_2 &= __constant_cpu_to_le32(
|
|
|
|
~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.process_response_queue = 0;
|
2005-10-27 12:09:48 -06:00
|
|
|
if (ha->zio_mode != QLA_ZIO_DISABLED) {
|
2006-03-09 15:27:39 -07:00
|
|
|
ha->zio_mode = QLA_ZIO_MODE_6;
|
|
|
|
|
2005-10-27 12:09:48 -06:00
|
|
|
DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
|
2008-11-06 11:40:51 -07:00
|
|
|
"(%d us).\n", vha->host_no, ha->zio_mode,
|
2005-10-27 12:09:48 -06:00
|
|
|
ha->zio_timer * 100));
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"ZIO mode %d enabled; timer delay (%d us).\n",
|
|
|
|
ha->zio_mode, ha->zio_timer * 100);
|
|
|
|
|
|
|
|
icb->firmware_options_2 |= cpu_to_le32(
|
|
|
|
(uint32_t)ha->zio_mode);
|
|
|
|
icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.process_response_queue = 1;
|
2005-10-27 12:09:48 -06:00
|
|
|
}
|
|
|
|
|
2007-04-16 13:37:43 -06:00
|
|
|
if (rval) {
|
|
|
|
DEBUG2_3(printk(KERN_WARNING
|
2008-11-06 11:40:51 -07:00
|
|
|
"scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
|
2007-04-16 13:37:43 -06:00
|
|
|
}
|
|
|
|
return (rval);
|
2005-07-06 11:31:37 -06:00
|
|
|
}
|
|
|
|
|
2006-06-30 03:33:06 -06:00
|
|
|
static int
|
2009-06-03 10:55:17 -06:00
|
|
|
qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
|
|
|
|
uint32_t faddr)
|
2006-05-17 16:09:00 -06:00
|
|
|
{
|
2008-12-09 17:45:39 -07:00
|
|
|
int rval = QLA_SUCCESS;
|
2006-05-17 16:09:00 -06:00
|
|
|
int segments, fragment;
|
|
|
|
uint32_t *dcode, dlen;
|
|
|
|
uint32_t risc_addr;
|
|
|
|
uint32_t risc_size;
|
|
|
|
uint32_t i;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
2009-01-22 10:45:32 -07:00
|
|
|
|
|
|
|
qla_printk(KERN_INFO, ha,
|
2009-06-03 10:55:17 -06:00
|
|
|
"FW: Loading from flash (%x)...\n", faddr);
|
2009-01-22 10:45:32 -07:00
|
|
|
|
2006-05-17 16:09:00 -06:00
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
|
|
|
|
segments = FA_RISC_CODE_SEGMENTS;
|
2008-12-09 17:45:39 -07:00
|
|
|
dcode = (uint32_t *)req->ring;
|
2006-05-17 16:09:00 -06:00
|
|
|
*srisc_addr = 0;
|
|
|
|
|
|
|
|
/* Validate firmware image by checking version. */
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_read_flash_data(vha, dcode, faddr + 4, 4);
|
2006-05-17 16:09:00 -06:00
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
dcode[i] = be32_to_cpu(dcode[i]);
|
|
|
|
if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
|
|
|
|
dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
|
|
|
|
(dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
|
|
|
|
dcode[3] == 0)) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to verify integrity of flash firmware image!\n");
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Firmware data: %08x %08x %08x %08x!\n", dcode[0],
|
|
|
|
dcode[1], dcode[2], dcode[3]);
|
|
|
|
|
|
|
|
return QLA_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (segments && rval == QLA_SUCCESS) {
|
|
|
|
/* Read segment's load information. */
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_read_flash_data(vha, dcode, faddr, 4);
|
2006-05-17 16:09:00 -06:00
|
|
|
|
|
|
|
risc_addr = be32_to_cpu(dcode[2]);
|
|
|
|
*srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
|
|
|
|
risc_size = be32_to_cpu(dcode[3]);
|
|
|
|
|
|
|
|
fragment = 0;
|
|
|
|
while (risc_size > 0 && rval == QLA_SUCCESS) {
|
|
|
|
dlen = (uint32_t)(ha->fw_transfer_size >> 2);
|
|
|
|
if (dlen > risc_size)
|
|
|
|
dlen = risc_size;
|
|
|
|
|
|
|
|
DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
|
|
|
|
"addr %x, number of dwords 0x%x, offset 0x%x.\n",
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->host_no, risc_addr, dlen, faddr));
|
2006-05-17 16:09:00 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_read_flash_data(vha, dcode, faddr, dlen);
|
2006-05-17 16:09:00 -06:00
|
|
|
for (i = 0; i < dlen; i++)
|
|
|
|
dcode[i] = swab32(dcode[i]);
|
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
rval = qla2x00_load_ram(vha, req->dma, risc_addr,
|
2006-05-17 16:09:00 -06:00
|
|
|
dlen);
|
|
|
|
if (rval) {
|
|
|
|
DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
|
2008-11-06 11:40:51 -07:00
|
|
|
"segment %d of firmware\n", vha->host_no,
|
2006-05-17 16:09:00 -06:00
|
|
|
fragment));
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"[ERROR] Failed to load segment %d of "
|
|
|
|
"firmware\n", fragment);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
faddr += dlen;
|
|
|
|
risc_addr += dlen;
|
|
|
|
risc_size -= dlen;
|
|
|
|
fragment++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next segment. */
|
|
|
|
segments--;
|
|
|
|
}
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define QLA_FW_URL "ftp://ftp.qlogic.com/outgoing/linux/firmware/"
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
2005-11-09 16:49:04 -07:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
int i, fragment;
|
|
|
|
uint16_t *wcode, *fwcode;
|
|
|
|
uint32_t risc_addr, risc_size, fwclen, wlen, *seg;
|
|
|
|
struct fw_blob *blob;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
2005-11-09 16:49:04 -07:00
|
|
|
|
|
|
|
/* Load firmware blob. */
|
2008-11-06 11:40:51 -07:00
|
|
|
blob = qla2x00_request_firmware(vha);
|
2005-11-09 16:49:04 -07:00
|
|
|
if (!blob) {
|
|
|
|
qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
|
2006-05-17 16:09:00 -06:00
|
|
|
qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
|
|
|
|
"from: " QLA_FW_URL ".\n");
|
2005-11-09 16:49:04 -07:00
|
|
|
return QLA_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
wcode = (uint16_t *)req->ring;
|
2005-11-09 16:49:04 -07:00
|
|
|
*srisc_addr = 0;
|
|
|
|
fwcode = (uint16_t *)blob->fw->data;
|
|
|
|
fwclen = 0;
|
|
|
|
|
|
|
|
/* Validate firmware image by checking version. */
|
|
|
|
if (blob->fw->size < 8 * sizeof(uint16_t)) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to verify integrity of firmware image (%Zd)!\n",
|
|
|
|
blob->fw->size);
|
|
|
|
goto fail_fw_integrity;
|
|
|
|
}
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
wcode[i] = be16_to_cpu(fwcode[i + 4]);
|
|
|
|
if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff &&
|
|
|
|
wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 &&
|
|
|
|
wcode[2] == 0 && wcode[3] == 0)) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to verify integrity of firmware image!\n");
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Firmware data: %04x %04x %04x %04x!\n", wcode[0],
|
|
|
|
wcode[1], wcode[2], wcode[3]);
|
|
|
|
goto fail_fw_integrity;
|
|
|
|
}
|
|
|
|
|
|
|
|
seg = blob->segs;
|
|
|
|
while (*seg && rval == QLA_SUCCESS) {
|
|
|
|
risc_addr = *seg;
|
|
|
|
*srisc_addr = *srisc_addr == 0 ? *seg : *srisc_addr;
|
|
|
|
risc_size = be16_to_cpu(fwcode[3]);
|
|
|
|
|
|
|
|
/* Validate firmware image size. */
|
|
|
|
fwclen += risc_size * sizeof(uint16_t);
|
|
|
|
if (blob->fw->size < fwclen) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to verify integrity of firmware image "
|
|
|
|
"(%Zd)!\n", blob->fw->size);
|
|
|
|
goto fail_fw_integrity;
|
|
|
|
}
|
|
|
|
|
|
|
|
fragment = 0;
|
|
|
|
while (risc_size > 0 && rval == QLA_SUCCESS) {
|
|
|
|
wlen = (uint16_t)(ha->fw_transfer_size >> 1);
|
|
|
|
if (wlen > risc_size)
|
|
|
|
wlen = risc_size;
|
|
|
|
|
|
|
|
DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
|
2008-11-06 11:40:51 -07:00
|
|
|
"addr %x, number of words 0x%x.\n", vha->host_no,
|
2005-11-09 16:49:04 -07:00
|
|
|
risc_addr, wlen));
|
|
|
|
|
|
|
|
for (i = 0; i < wlen; i++)
|
|
|
|
wcode[i] = swab16(fwcode[i]);
|
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
rval = qla2x00_load_ram(vha, req->dma, risc_addr,
|
2005-11-09 16:49:04 -07:00
|
|
|
wlen);
|
|
|
|
if (rval) {
|
|
|
|
DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
|
2008-11-06 11:40:51 -07:00
|
|
|
"segment %d of firmware\n", vha->host_no,
|
2005-11-09 16:49:04 -07:00
|
|
|
fragment));
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"[ERROR] Failed to load segment %d of "
|
|
|
|
"firmware\n", fragment);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fwcode += wlen;
|
|
|
|
risc_addr += wlen;
|
|
|
|
risc_size -= wlen;
|
|
|
|
fragment++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next segment. */
|
|
|
|
seg++;
|
|
|
|
}
|
|
|
|
return rval;
|
|
|
|
|
|
|
|
fail_fw_integrity:
|
|
|
|
return QLA_FUNCTION_FAILED;
|
|
|
|
}
|
|
|
|
|
2009-01-22 10:45:32 -07:00
|
|
|
static int
|
|
|
|
qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
2005-07-06 11:31:37 -06:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
int segments, fragment;
|
|
|
|
uint32_t *dcode, dlen;
|
|
|
|
uint32_t risc_addr;
|
|
|
|
uint32_t risc_size;
|
|
|
|
uint32_t i;
|
2005-11-09 16:49:04 -07:00
|
|
|
struct fw_blob *blob;
|
2005-07-06 11:31:37 -06:00
|
|
|
uint32_t *fwcode, fwclen;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-12-09 17:45:39 -07:00
|
|
|
struct req_que *req = ha->req_q_map[0];
|
2005-07-06 11:31:37 -06:00
|
|
|
|
2005-11-09 16:49:04 -07:00
|
|
|
/* Load firmware blob. */
|
2008-11-06 11:40:51 -07:00
|
|
|
blob = qla2x00_request_firmware(vha);
|
2005-11-09 16:49:04 -07:00
|
|
|
if (!blob) {
|
|
|
|
qla_printk(KERN_ERR, ha, "Firmware image unavailable.\n");
|
2006-05-17 16:09:00 -06:00
|
|
|
qla_printk(KERN_ERR, ha, "Firmware images can be retrieved "
|
|
|
|
"from: " QLA_FW_URL ".\n");
|
|
|
|
|
2009-01-22 10:45:32 -07:00
|
|
|
return QLA_FUNCTION_FAILED;
|
2005-07-06 11:31:37 -06:00
|
|
|
}
|
|
|
|
|
2009-01-22 10:45:32 -07:00
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"FW: Loading via request-firmware...\n");
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
|
|
|
|
segments = FA_RISC_CODE_SEGMENTS;
|
2008-12-09 17:45:39 -07:00
|
|
|
dcode = (uint32_t *)req->ring;
|
2005-07-06 11:31:37 -06:00
|
|
|
*srisc_addr = 0;
|
2005-11-09 16:49:04 -07:00
|
|
|
fwcode = (uint32_t *)blob->fw->data;
|
2005-07-06 11:31:37 -06:00
|
|
|
fwclen = 0;
|
|
|
|
|
|
|
|
/* Validate firmware image by checking version. */
|
2005-11-09 16:49:04 -07:00
|
|
|
if (blob->fw->size < 8 * sizeof(uint32_t)) {
|
2005-07-06 11:31:37 -06:00
|
|
|
qla_printk(KERN_WARNING, ha,
|
2005-11-09 16:49:04 -07:00
|
|
|
"Unable to verify integrity of firmware image (%Zd)!\n",
|
|
|
|
blob->fw->size);
|
2005-07-06 11:31:37 -06:00
|
|
|
goto fail_fw_integrity;
|
|
|
|
}
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
dcode[i] = be32_to_cpu(fwcode[i + 4]);
|
|
|
|
if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff &&
|
|
|
|
dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) ||
|
|
|
|
(dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
|
|
|
|
dcode[3] == 0)) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
2005-11-09 16:49:04 -07:00
|
|
|
"Unable to verify integrity of firmware image!\n");
|
2005-07-06 11:31:37 -06:00
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Firmware data: %08x %08x %08x %08x!\n", dcode[0],
|
|
|
|
dcode[1], dcode[2], dcode[3]);
|
|
|
|
goto fail_fw_integrity;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (segments && rval == QLA_SUCCESS) {
|
|
|
|
risc_addr = be32_to_cpu(fwcode[2]);
|
|
|
|
*srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr;
|
|
|
|
risc_size = be32_to_cpu(fwcode[3]);
|
|
|
|
|
|
|
|
/* Validate firmware image size. */
|
|
|
|
fwclen += risc_size * sizeof(uint32_t);
|
2005-11-09 16:49:04 -07:00
|
|
|
if (blob->fw->size < fwclen) {
|
2005-07-06 11:31:37 -06:00
|
|
|
qla_printk(KERN_WARNING, ha,
|
2005-11-09 16:49:04 -07:00
|
|
|
"Unable to verify integrity of firmware image "
|
|
|
|
"(%Zd)!\n", blob->fw->size);
|
|
|
|
|
2005-07-06 11:31:37 -06:00
|
|
|
goto fail_fw_integrity;
|
|
|
|
}
|
|
|
|
|
|
|
|
fragment = 0;
|
|
|
|
while (risc_size > 0 && rval == QLA_SUCCESS) {
|
|
|
|
dlen = (uint32_t)(ha->fw_transfer_size >> 2);
|
|
|
|
if (dlen > risc_size)
|
|
|
|
dlen = risc_size;
|
|
|
|
|
|
|
|
DEBUG7(printk("scsi(%ld): Loading risc segment@ risc "
|
2008-11-06 11:40:51 -07:00
|
|
|
"addr %x, number of dwords 0x%x.\n", vha->host_no,
|
2005-07-06 11:31:37 -06:00
|
|
|
risc_addr, dlen));
|
|
|
|
|
|
|
|
for (i = 0; i < dlen; i++)
|
|
|
|
dcode[i] = swab32(fwcode[i]);
|
|
|
|
|
2008-12-09 17:45:39 -07:00
|
|
|
rval = qla2x00_load_ram(vha, req->dma, risc_addr,
|
2006-01-13 18:05:37 -07:00
|
|
|
dlen);
|
2005-07-06 11:31:37 -06:00
|
|
|
if (rval) {
|
|
|
|
DEBUG(printk("scsi(%ld):[ERROR] Failed to load "
|
2008-11-06 11:40:51 -07:00
|
|
|
"segment %d of firmware\n", vha->host_no,
|
2005-07-06 11:31:37 -06:00
|
|
|
fragment));
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"[ERROR] Failed to load segment %d of "
|
|
|
|
"firmware\n", fragment);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fwcode += dlen;
|
|
|
|
risc_addr += dlen;
|
|
|
|
risc_size -= dlen;
|
|
|
|
fragment++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Next segment. */
|
|
|
|
segments--;
|
|
|
|
}
|
|
|
|
return rval;
|
|
|
|
|
|
|
|
fail_fw_integrity:
|
|
|
|
return QLA_FUNCTION_FAILED;
|
|
|
|
}
|
2006-10-13 10:33:38 -06:00
|
|
|
|
2009-01-22 10:45:32 -07:00
|
|
|
int
|
|
|
|
qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
|
2009-04-06 23:33:49 -06:00
|
|
|
if (ql2xfwloadbin == 1)
|
|
|
|
return qla81xx_load_risc(vha, srisc_addr);
|
|
|
|
|
2009-01-22 10:45:32 -07:00
|
|
|
/*
|
|
|
|
* FW Load priority:
|
|
|
|
* 1) Firmware via request-firmware interface (.bin file).
|
|
|
|
* 2) Firmware residing in flash.
|
|
|
|
*/
|
|
|
|
rval = qla24xx_load_risc_blob(vha, srisc_addr);
|
|
|
|
if (rval == QLA_SUCCESS)
|
|
|
|
return rval;
|
|
|
|
|
2009-06-03 10:55:17 -06:00
|
|
|
return qla24xx_load_risc_flash(vha, srisc_addr,
|
|
|
|
vha->hw->flt_region_fw);
|
2009-01-22 10:45:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
|
|
|
{
|
|
|
|
int rval;
|
2009-06-03 10:55:17 -06:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2009-01-22 10:45:32 -07:00
|
|
|
|
2009-04-06 23:33:49 -06:00
|
|
|
if (ql2xfwloadbin == 2)
|
2009-06-03 10:55:17 -06:00
|
|
|
goto try_blob_fw;
|
2009-04-06 23:33:49 -06:00
|
|
|
|
2009-01-22 10:45:32 -07:00
|
|
|
/*
|
|
|
|
* FW Load priority:
|
|
|
|
* 1) Firmware residing in flash.
|
|
|
|
* 2) Firmware via request-firmware interface (.bin file).
|
2009-06-03 10:55:17 -06:00
|
|
|
* 3) Golden-Firmware residing in flash -- limited operation.
|
2009-01-22 10:45:32 -07:00
|
|
|
*/
|
2009-06-03 10:55:17 -06:00
|
|
|
rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw);
|
2009-01-22 10:45:32 -07:00
|
|
|
if (rval == QLA_SUCCESS)
|
|
|
|
return rval;
|
|
|
|
|
2009-06-03 10:55:17 -06:00
|
|
|
try_blob_fw:
|
|
|
|
rval = qla24xx_load_risc_blob(vha, srisc_addr);
|
|
|
|
if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw)
|
|
|
|
return rval;
|
|
|
|
|
|
|
|
qla_printk(KERN_ERR, ha,
|
|
|
|
"FW: Attempting to fallback to golden firmware...\n");
|
|
|
|
rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw);
|
|
|
|
if (rval != QLA_SUCCESS)
|
|
|
|
return rval;
|
|
|
|
|
|
|
|
qla_printk(KERN_ERR, ha,
|
|
|
|
"FW: Please update operational firmware...\n");
|
|
|
|
ha->flags.running_gold_fw = 1;
|
|
|
|
|
|
|
|
return rval;
|
2009-01-22 10:45:32 -07:00
|
|
|
}
|
|
|
|
|
2006-10-13 10:33:38 -06:00
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
|
2006-10-13 10:33:38 -06:00
|
|
|
{
|
|
|
|
int ret, retries;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2006-10-13 10:33:38 -06:00
|
|
|
|
2009-12-15 22:29:46 -07:00
|
|
|
if (ha->flags.pci_channel_io_perm_failure)
|
|
|
|
return;
|
2007-07-19 16:05:56 -06:00
|
|
|
if (!IS_FWI2_CAPABLE(ha))
|
2006-10-13 10:33:38 -06:00
|
|
|
return;
|
2007-05-07 08:43:00 -06:00
|
|
|
if (!ha->fw_major_version)
|
|
|
|
return;
|
2006-10-13 10:33:38 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
ret = qla2x00_stop_firmware(vha);
|
2008-02-28 15:06:09 -07:00
|
|
|
for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT &&
|
2009-04-06 23:33:48 -06:00
|
|
|
ret != QLA_INVALID_COMMAND && retries ; retries--) {
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->reset_chip(vha);
|
|
|
|
if (ha->isp_ops->chip_diag(vha) != QLA_SUCCESS)
|
2006-10-13 10:33:38 -06:00
|
|
|
continue;
|
2008-11-06 11:40:51 -07:00
|
|
|
if (qla2x00_setup_chip(vha) != QLA_SUCCESS)
|
2006-10-13 10:33:38 -06:00
|
|
|
continue;
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"Attempting retry of stop-firmware command...\n");
|
2008-11-06 11:40:51 -07:00
|
|
|
ret = qla2x00_stop_firmware(vha);
|
2006-10-13 10:33:38 -06:00
|
|
|
}
|
|
|
|
}
|
2007-07-05 14:16:51 -06:00
|
|
|
|
|
|
|
int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla24xx_configure_vhba(scsi_qla_host_t *vha)
|
2007-07-05 14:16:51 -06:00
|
|
|
{
|
|
|
|
int rval = QLA_SUCCESS;
|
|
|
|
uint16_t mb[MAILBOX_REGISTER_COUNT];
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
|
2009-04-06 23:33:42 -06:00
|
|
|
struct req_que *req;
|
|
|
|
struct rsp_que *rsp;
|
2007-07-05 14:16:51 -06:00
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
if (!vha->vp_idx)
|
2007-07-05 14:16:51 -06:00
|
|
|
return -EINVAL;
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla2x00_fw_ready(base_vha);
|
2009-08-05 10:18:40 -06:00
|
|
|
if (ha->flags.cpu_affinity_enabled)
|
2009-04-06 23:33:42 -06:00
|
|
|
req = ha->req_q_map[0];
|
|
|
|
else
|
|
|
|
req = vha->req;
|
|
|
|
rsp = req->rsp;
|
|
|
|
|
2007-07-05 14:16:51 -06:00
|
|
|
if (rval == QLA_SUCCESS) {
|
2008-11-06 11:40:51 -07:00
|
|
|
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
2008-12-09 17:45:39 -07:00
|
|
|
qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
|
2007-07-05 14:16:51 -06:00
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
vha->flags.management_server_logged_in = 0;
|
2007-07-05 14:16:51 -06:00
|
|
|
|
|
|
|
/* Login to SNS first */
|
2008-11-06 11:40:51 -07:00
|
|
|
ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb, BIT_1);
|
2007-07-05 14:16:51 -06:00
|
|
|
if (mb[0] != MBS_COMMAND_COMPLETE) {
|
|
|
|
DEBUG15(qla_printk(KERN_INFO, ha,
|
|
|
|
"Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
|
|
|
|
"mb[2]=%x mb[6]=%x mb[7]=%x\n", NPH_SNS,
|
|
|
|
mb[0], mb[1], mb[2], mb[6], mb[7]));
|
|
|
|
return (QLA_FUNCTION_FAILED);
|
|
|
|
}
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
atomic_set(&vha->loop_down_timer, 0);
|
|
|
|
atomic_set(&vha->loop_state, LOOP_UP);
|
|
|
|
set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
|
|
|
set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
|
|
|
|
rval = qla2x00_loop_resync(base_vha);
|
2007-07-05 14:16:51 -06:00
|
|
|
|
|
|
|
return rval;
|
|
|
|
}
|
2008-04-03 14:13:26 -06:00
|
|
|
|
|
|
|
/* 84XX Support **************************************************************/
|
|
|
|
|
|
|
|
static LIST_HEAD(qla_cs84xx_list);
|
|
|
|
static DEFINE_MUTEX(qla_cs84xx_mutex);
|
|
|
|
|
|
|
|
static struct qla_chip_state_84xx *
|
2008-11-06 11:40:51 -07:00
|
|
|
qla84xx_get_chip(struct scsi_qla_host *vha)
|
2008-04-03 14:13:26 -06:00
|
|
|
{
|
|
|
|
struct qla_chip_state_84xx *cs84xx;
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-04-03 14:13:26 -06:00
|
|
|
|
|
|
|
mutex_lock(&qla_cs84xx_mutex);
|
|
|
|
|
|
|
|
/* Find any shared 84xx chip. */
|
|
|
|
list_for_each_entry(cs84xx, &qla_cs84xx_list, list) {
|
|
|
|
if (cs84xx->bus == ha->pdev->bus) {
|
|
|
|
kref_get(&cs84xx->kref);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL);
|
|
|
|
if (!cs84xx)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
kref_init(&cs84xx->kref);
|
|
|
|
spin_lock_init(&cs84xx->access_lock);
|
|
|
|
mutex_init(&cs84xx->fw_update_mutex);
|
|
|
|
cs84xx->bus = ha->pdev->bus;
|
|
|
|
|
|
|
|
list_add_tail(&cs84xx->list, &qla_cs84xx_list);
|
|
|
|
done:
|
|
|
|
mutex_unlock(&qla_cs84xx_mutex);
|
|
|
|
return cs84xx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
__qla84xx_chip_release(struct kref *kref)
|
|
|
|
{
|
|
|
|
struct qla_chip_state_84xx *cs84xx =
|
|
|
|
container_of(kref, struct qla_chip_state_84xx, kref);
|
|
|
|
|
|
|
|
mutex_lock(&qla_cs84xx_mutex);
|
|
|
|
list_del(&cs84xx->list);
|
|
|
|
mutex_unlock(&qla_cs84xx_mutex);
|
|
|
|
kfree(cs84xx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-11-06 11:40:51 -07:00
|
|
|
qla84xx_put_chip(struct scsi_qla_host *vha)
|
2008-04-03 14:13:26 -06:00
|
|
|
{
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-04-03 14:13:26 -06:00
|
|
|
if (ha->cs84xx)
|
|
|
|
kref_put(&ha->cs84xx->kref, __qla84xx_chip_release);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2008-11-06 11:40:51 -07:00
|
|
|
qla84xx_init_chip(scsi_qla_host_t *vha)
|
2008-04-03 14:13:26 -06:00
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
uint16_t status[2];
|
2008-11-06 11:40:51 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
2008-04-03 14:13:26 -06:00
|
|
|
|
|
|
|
mutex_lock(&ha->cs84xx->fw_update_mutex);
|
|
|
|
|
2008-11-06 11:40:51 -07:00
|
|
|
rval = qla84xx_verify_chip(vha, status);
|
2008-04-03 14:13:26 -06:00
|
|
|
|
|
|
|
mutex_unlock(&ha->cs84xx->fw_update_mutex);
|
|
|
|
|
|
|
|
return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED:
|
|
|
|
QLA_SUCCESS;
|
|
|
|
}
|
2009-01-05 12:18:11 -07:00
|
|
|
|
|
|
|
/* 81XX Support **************************************************************/
|
|
|
|
|
|
|
|
int
|
|
|
|
qla81xx_nvram_config(scsi_qla_host_t *vha)
|
|
|
|
{
|
|
|
|
int rval;
|
|
|
|
struct init_cb_81xx *icb;
|
|
|
|
struct nvram_81xx *nv;
|
|
|
|
uint32_t *dptr;
|
|
|
|
uint8_t *dptr1, *dptr2;
|
|
|
|
uint32_t chksum;
|
|
|
|
uint16_t cnt;
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
|
|
|
|
rval = QLA_SUCCESS;
|
|
|
|
icb = (struct init_cb_81xx *)ha->init_cb;
|
|
|
|
nv = ha->nvram;
|
|
|
|
|
|
|
|
/* Determine NVRAM starting address. */
|
|
|
|
ha->nvram_size = sizeof(struct nvram_81xx);
|
|
|
|
ha->vpd_size = FA_NVRAM_VPD_SIZE;
|
|
|
|
|
|
|
|
/* Get VPD data into cache */
|
|
|
|
ha->vpd = ha->nvram + VPD_OFFSET;
|
2009-03-24 10:08:14 -06:00
|
|
|
ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2,
|
|
|
|
ha->vpd_size);
|
2009-01-05 12:18:11 -07:00
|
|
|
|
|
|
|
/* Get NVRAM data into cache and calculate checksum. */
|
2009-03-24 10:08:14 -06:00
|
|
|
ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2,
|
2009-01-05 12:18:11 -07:00
|
|
|
ha->nvram_size);
|
2009-03-24 10:08:14 -06:00
|
|
|
dptr = (uint32_t *)nv;
|
2009-01-05 12:18:11 -07:00
|
|
|
for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++)
|
|
|
|
chksum += le32_to_cpu(*dptr++);
|
|
|
|
|
2009-04-06 23:33:39 -06:00
|
|
|
DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", vha->host_no));
|
2009-01-05 12:18:11 -07:00
|
|
|
DEBUG5(qla2x00_dump_buffer((uint8_t *)nv, ha->nvram_size));
|
|
|
|
|
|
|
|
/* Bad NVRAM data, set defaults parameters. */
|
|
|
|
if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P'
|
|
|
|
|| nv->id[3] != ' ' ||
|
|
|
|
nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) {
|
|
|
|
/* Reset NVRAM data. */
|
|
|
|
qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
|
|
|
|
"checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
|
|
|
|
le16_to_cpu(nv->nvram_version));
|
|
|
|
qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
|
|
|
|
"invalid -- WWPN) defaults.\n");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set default initialization control block.
|
|
|
|
*/
|
|
|
|
memset(nv, 0, ha->nvram_size);
|
|
|
|
nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION);
|
|
|
|
nv->version = __constant_cpu_to_le16(ICB_VERSION);
|
|
|
|
nv->frame_payload_size = __constant_cpu_to_le16(2048);
|
|
|
|
nv->execution_throttle = __constant_cpu_to_le16(0xFFFF);
|
|
|
|
nv->exchange_count = __constant_cpu_to_le16(0);
|
|
|
|
nv->port_name[0] = 0x21;
|
2009-04-06 23:33:50 -06:00
|
|
|
nv->port_name[1] = 0x00 + ha->port_no;
|
2009-01-05 12:18:11 -07:00
|
|
|
nv->port_name[2] = 0x00;
|
|
|
|
nv->port_name[3] = 0xe0;
|
|
|
|
nv->port_name[4] = 0x8b;
|
|
|
|
nv->port_name[5] = 0x1c;
|
|
|
|
nv->port_name[6] = 0x55;
|
|
|
|
nv->port_name[7] = 0x86;
|
|
|
|
nv->node_name[0] = 0x20;
|
|
|
|
nv->node_name[1] = 0x00;
|
|
|
|
nv->node_name[2] = 0x00;
|
|
|
|
nv->node_name[3] = 0xe0;
|
|
|
|
nv->node_name[4] = 0x8b;
|
|
|
|
nv->node_name[5] = 0x1c;
|
|
|
|
nv->node_name[6] = 0x55;
|
|
|
|
nv->node_name[7] = 0x86;
|
|
|
|
nv->login_retry_count = __constant_cpu_to_le16(8);
|
|
|
|
nv->interrupt_delay_timer = __constant_cpu_to_le16(0);
|
|
|
|
nv->login_timeout = __constant_cpu_to_le16(0);
|
|
|
|
nv->firmware_options_1 =
|
|
|
|
__constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
|
|
|
|
nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4);
|
|
|
|
nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12);
|
|
|
|
nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13);
|
|
|
|
nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10);
|
|
|
|
nv->efi_parameters = __constant_cpu_to_le32(0);
|
|
|
|
nv->reset_delay = 5;
|
|
|
|
nv->max_luns_per_target = __constant_cpu_to_le16(128);
|
|
|
|
nv->port_down_retry_count = __constant_cpu_to_le16(30);
|
|
|
|
nv->link_down_timeout = __constant_cpu_to_le16(30);
|
2009-06-03 10:55:24 -06:00
|
|
|
nv->enode_mac[0] = 0x00;
|
2009-01-05 12:18:11 -07:00
|
|
|
nv->enode_mac[1] = 0x02;
|
|
|
|
nv->enode_mac[2] = 0x03;
|
|
|
|
nv->enode_mac[3] = 0x04;
|
|
|
|
nv->enode_mac[4] = 0x05;
|
2009-04-06 23:33:50 -06:00
|
|
|
nv->enode_mac[5] = 0x06 + ha->port_no;
|
2009-01-05 12:18:11 -07:00
|
|
|
|
|
|
|
rval = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset Initialization control block */
|
|
|
|
memset(icb, 0, sizeof(struct init_cb_81xx));
|
|
|
|
|
|
|
|
/* Copy 1st segment. */
|
|
|
|
dptr1 = (uint8_t *)icb;
|
|
|
|
dptr2 = (uint8_t *)&nv->version;
|
|
|
|
cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version;
|
|
|
|
while (cnt--)
|
|
|
|
*dptr1++ = *dptr2++;
|
|
|
|
|
|
|
|
icb->login_retry_count = nv->login_retry_count;
|
|
|
|
|
|
|
|
/* Copy 2nd segment. */
|
|
|
|
dptr1 = (uint8_t *)&icb->interrupt_delay_timer;
|
|
|
|
dptr2 = (uint8_t *)&nv->interrupt_delay_timer;
|
|
|
|
cnt = (uint8_t *)&icb->reserved_5 -
|
|
|
|
(uint8_t *)&icb->interrupt_delay_timer;
|
|
|
|
while (cnt--)
|
|
|
|
*dptr1++ = *dptr2++;
|
|
|
|
|
|
|
|
memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac));
|
|
|
|
/* Some boards (with valid NVRAMs) still have NULL enode_mac!! */
|
|
|
|
if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) {
|
|
|
|
icb->enode_mac[0] = 0x01;
|
|
|
|
icb->enode_mac[1] = 0x02;
|
|
|
|
icb->enode_mac[2] = 0x03;
|
|
|
|
icb->enode_mac[3] = 0x04;
|
|
|
|
icb->enode_mac[4] = 0x05;
|
2009-04-06 23:33:50 -06:00
|
|
|
icb->enode_mac[5] = 0x06 + ha->port_no;
|
2009-01-05 12:18:11 -07:00
|
|
|
}
|
|
|
|
|
2009-03-24 10:08:01 -06:00
|
|
|
/* Use extended-initialization control block. */
|
|
|
|
memcpy(ha->ex_init_cb, &nv->ex_version, sizeof(*ha->ex_init_cb));
|
|
|
|
|
2009-01-05 12:18:11 -07:00
|
|
|
/*
|
|
|
|
* Setup driver NVRAM options.
|
|
|
|
*/
|
|
|
|
qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name),
|
2010-04-12 18:59:55 -06:00
|
|
|
"QLE8XXX");
|
2009-01-05 12:18:11 -07:00
|
|
|
|
|
|
|
/* Use alternate WWN? */
|
|
|
|
if (nv->host_p & __constant_cpu_to_le32(BIT_15)) {
|
|
|
|
memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE);
|
|
|
|
memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Prepare nodename */
|
|
|
|
if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) {
|
|
|
|
/*
|
|
|
|
* Firmware will apply the following mask if the nodename was
|
|
|
|
* not provided.
|
|
|
|
*/
|
|
|
|
memcpy(icb->node_name, icb->port_name, WWN_SIZE);
|
|
|
|
icb->node_name[0] &= 0xF0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set host adapter parameters. */
|
|
|
|
ha->flags.disable_risc_code_load = 0;
|
|
|
|
ha->flags.enable_lip_reset = 0;
|
|
|
|
ha->flags.enable_lip_full_login =
|
|
|
|
le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0;
|
|
|
|
ha->flags.enable_target_reset =
|
|
|
|
le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0;
|
|
|
|
ha->flags.enable_led_scheme = 0;
|
|
|
|
ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0;
|
|
|
|
|
|
|
|
ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) &
|
|
|
|
(BIT_6 | BIT_5 | BIT_4)) >> 4;
|
|
|
|
|
|
|
|
/* save HBA serial number */
|
|
|
|
ha->serial0 = icb->port_name[5];
|
|
|
|
ha->serial1 = icb->port_name[6];
|
|
|
|
ha->serial2 = icb->port_name[7];
|
|
|
|
memcpy(vha->node_name, icb->node_name, WWN_SIZE);
|
|
|
|
memcpy(vha->port_name, icb->port_name, WWN_SIZE);
|
|
|
|
|
|
|
|
icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
|
|
|
|
|
|
|
|
ha->retry_count = le16_to_cpu(nv->login_retry_count);
|
|
|
|
|
|
|
|
/* Set minimum login_timeout to 4 seconds. */
|
|
|
|
if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout)
|
|
|
|
nv->login_timeout = cpu_to_le16(ql2xlogintimeout);
|
|
|
|
if (le16_to_cpu(nv->login_timeout) < 4)
|
|
|
|
nv->login_timeout = __constant_cpu_to_le16(4);
|
|
|
|
ha->login_timeout = le16_to_cpu(nv->login_timeout);
|
|
|
|
icb->login_timeout = nv->login_timeout;
|
|
|
|
|
|
|
|
/* Set minimum RATOV to 100 tenths of a second. */
|
|
|
|
ha->r_a_tov = 100;
|
|
|
|
|
|
|
|
ha->loop_reset_delay = nv->reset_delay;
|
|
|
|
|
|
|
|
/* Link Down Timeout = 0:
|
|
|
|
*
|
|
|
|
* When Port Down timer expires we will start returning
|
|
|
|
* I/O's to OS with "DID_NO_CONNECT".
|
|
|
|
*
|
|
|
|
* Link Down Timeout != 0:
|
|
|
|
*
|
|
|
|
* The driver waits for the link to come up after link down
|
|
|
|
* before returning I/Os to OS with "DID_NO_CONNECT".
|
|
|
|
*/
|
|
|
|
if (le16_to_cpu(nv->link_down_timeout) == 0) {
|
|
|
|
ha->loop_down_abort_time =
|
|
|
|
(LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT);
|
|
|
|
} else {
|
|
|
|
ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout);
|
|
|
|
ha->loop_down_abort_time =
|
|
|
|
(LOOP_DOWN_TIME - ha->link_down_timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Need enough time to try and get the port back. */
|
|
|
|
ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count);
|
|
|
|
if (qlport_down_retry)
|
|
|
|
ha->port_down_retry_count = qlport_down_retry;
|
|
|
|
|
|
|
|
/* Set login_retry_count */
|
|
|
|
ha->login_retry_count = le16_to_cpu(nv->login_retry_count);
|
|
|
|
if (ha->port_down_retry_count ==
|
|
|
|
le16_to_cpu(nv->port_down_retry_count) &&
|
|
|
|
ha->port_down_retry_count > 3)
|
|
|
|
ha->login_retry_count = ha->port_down_retry_count;
|
|
|
|
else if (ha->port_down_retry_count > (int)ha->login_retry_count)
|
|
|
|
ha->login_retry_count = ha->port_down_retry_count;
|
|
|
|
if (ql2xloginretrycount)
|
|
|
|
ha->login_retry_count = ql2xloginretrycount;
|
|
|
|
|
|
|
|
/* Enable ZIO. */
|
|
|
|
if (!vha->flags.init_done) {
|
|
|
|
ha->zio_mode = le32_to_cpu(icb->firmware_options_2) &
|
|
|
|
(BIT_3 | BIT_2 | BIT_1 | BIT_0);
|
|
|
|
ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ?
|
|
|
|
le16_to_cpu(icb->interrupt_delay_timer): 2;
|
|
|
|
}
|
|
|
|
icb->firmware_options_2 &= __constant_cpu_to_le32(
|
|
|
|
~(BIT_3 | BIT_2 | BIT_1 | BIT_0));
|
|
|
|
vha->flags.process_response_queue = 0;
|
|
|
|
if (ha->zio_mode != QLA_ZIO_DISABLED) {
|
|
|
|
ha->zio_mode = QLA_ZIO_MODE_6;
|
|
|
|
|
|
|
|
DEBUG2(printk("scsi(%ld): ZIO mode %d enabled; timer delay "
|
|
|
|
"(%d us).\n", vha->host_no, ha->zio_mode,
|
|
|
|
ha->zio_timer * 100));
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"ZIO mode %d enabled; timer delay (%d us).\n",
|
|
|
|
ha->zio_mode, ha->zio_timer * 100);
|
|
|
|
|
|
|
|
icb->firmware_options_2 |= cpu_to_le32(
|
|
|
|
(uint32_t)ha->zio_mode);
|
|
|
|
icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer);
|
|
|
|
vha->flags.process_response_queue = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rval) {
|
|
|
|
DEBUG2_3(printk(KERN_WARNING
|
|
|
|
"scsi(%ld): NVRAM configuration failed!\n", vha->host_no));
|
|
|
|
}
|
|
|
|
return (rval);
|
|
|
|
}
|
|
|
|
|
2010-04-12 18:59:55 -06:00
|
|
|
int
|
|
|
|
qla82xx_restart_isp(scsi_qla_host_t *vha)
|
|
|
|
{
|
|
|
|
int status, rval;
|
|
|
|
uint32_t wait_time;
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
struct req_que *req = ha->req_q_map[0];
|
|
|
|
struct rsp_que *rsp = ha->rsp_q_map[0];
|
|
|
|
struct scsi_qla_host *vp;
|
|
|
|
struct scsi_qla_host *tvp;
|
|
|
|
|
|
|
|
status = qla2x00_init_rings(vha);
|
|
|
|
if (!status) {
|
|
|
|
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
|
|
|
ha->flags.chip_reset_done = 1;
|
|
|
|
|
|
|
|
status = qla2x00_fw_ready(vha);
|
|
|
|
if (!status) {
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"%s(): Start configure loop, "
|
|
|
|
"status = %d\n", __func__, status);
|
|
|
|
|
|
|
|
/* Issue a marker after FW becomes ready. */
|
|
|
|
qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL);
|
|
|
|
|
|
|
|
vha->flags.online = 1;
|
|
|
|
/* Wait at most MAX_TARGET RSCNs for a stable link. */
|
|
|
|
wait_time = 256;
|
|
|
|
do {
|
|
|
|
clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
|
|
|
|
qla2x00_configure_loop(vha);
|
|
|
|
wait_time--;
|
|
|
|
} while (!atomic_read(&vha->loop_down_timer) &&
|
|
|
|
!(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) &&
|
|
|
|
wait_time &&
|
|
|
|
(test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if no cable then assume it's good */
|
|
|
|
if ((vha->device_flags & DFLG_NO_CABLE))
|
|
|
|
status = 0;
|
|
|
|
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"%s(): Configure loop done, status = 0x%x\n",
|
|
|
|
__func__, status);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!status) {
|
|
|
|
clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
|
|
|
|
|
|
|
|
if (!atomic_read(&vha->loop_down_timer)) {
|
|
|
|
/*
|
|
|
|
* Issue marker command only when we are going
|
|
|
|
* to start the I/O .
|
|
|
|
*/
|
|
|
|
vha->marker_needed = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
vha->flags.online = 1;
|
|
|
|
|
|
|
|
ha->isp_ops->enable_intrs(ha);
|
|
|
|
|
|
|
|
ha->isp_abort_cnt = 0;
|
|
|
|
clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
|
|
|
|
|
|
|
|
if (ha->fce) {
|
|
|
|
ha->flags.fce_enabled = 1;
|
|
|
|
memset(ha->fce, 0,
|
|
|
|
fce_calc_size(ha->fce_bufs));
|
|
|
|
rval = qla2x00_enable_fce_trace(vha,
|
|
|
|
ha->fce_dma, ha->fce_bufs, ha->fce_mb,
|
|
|
|
&ha->fce_bufs);
|
|
|
|
if (rval) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to reinitialize FCE "
|
|
|
|
"(%d).\n", rval);
|
|
|
|
ha->flags.fce_enabled = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ha->eft) {
|
|
|
|
memset(ha->eft, 0, EFT_SIZE);
|
|
|
|
rval = qla2x00_enable_eft_trace(vha,
|
|
|
|
ha->eft_dma, EFT_NUM_BUFFERS);
|
|
|
|
if (rval) {
|
|
|
|
qla_printk(KERN_WARNING, ha,
|
|
|
|
"Unable to reinitialize EFT "
|
|
|
|
"(%d).\n", rval);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!status) {
|
|
|
|
DEBUG(printk(KERN_INFO
|
|
|
|
"qla82xx_restart_isp(%ld): succeeded.\n",
|
|
|
|
vha->host_no));
|
|
|
|
list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) {
|
|
|
|
if (vp->vp_idx)
|
|
|
|
qla2x00_vp_abort_isp(vp);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
qla_printk(KERN_INFO, ha,
|
|
|
|
"qla82xx_restart_isp: **** FAILED ****\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2009-01-05 12:18:11 -07:00
|
|
|
void
|
2010-02-18 11:07:28 -07:00
|
|
|
qla81xx_update_fw_options(scsi_qla_host_t *vha)
|
2009-01-05 12:18:11 -07:00
|
|
|
{
|
2010-02-18 11:07:28 -07:00
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
|
|
|
|
if (!ql2xetsenable)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Enable ETS Burst. */
|
|
|
|
memset(ha->fw_options, 0, sizeof(ha->fw_options));
|
|
|
|
ha->fw_options[2] |= BIT_9;
|
|
|
|
qla2x00_set_fw_options(vha, ha->fw_options);
|
2009-01-05 12:18:11 -07:00
|
|
|
}
|
2010-03-19 18:03:59 -06:00
|
|
|
|
|
|
|
/*
|
|
|
|
* qla24xx_get_fcp_prio
|
|
|
|
* Gets the fcp cmd priority value for the logged in port.
|
|
|
|
* Looks for a match of the port descriptors within
|
|
|
|
* each of the fcp prio config entries. If a match is found,
|
|
|
|
* the tag (priority) value is returned.
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block po
|
|
|
|
* fcport = port structure pointer.
|
|
|
|
*
|
|
|
|
* Return:
|
2010-03-19 18:04:02 -06:00
|
|
|
* non-zero (if found)
|
2010-03-19 18:03:59 -06:00
|
|
|
* 0 (if not found)
|
|
|
|
*
|
|
|
|
* Context:
|
|
|
|
* Kernel context
|
|
|
|
*/
|
|
|
|
uint8_t
|
|
|
|
qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport)
|
|
|
|
{
|
|
|
|
int i, entries;
|
|
|
|
uint8_t pid_match, wwn_match;
|
|
|
|
uint8_t priority;
|
|
|
|
uint32_t pid1, pid2;
|
|
|
|
uint64_t wwn1, wwn2;
|
|
|
|
struct qla_fcp_prio_entry *pri_entry;
|
|
|
|
struct qla_hw_data *ha = vha->hw;
|
|
|
|
|
|
|
|
if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
priority = 0;
|
|
|
|
entries = ha->fcp_prio_cfg->num_entries;
|
|
|
|
pri_entry = &ha->fcp_prio_cfg->entry[0];
|
|
|
|
|
|
|
|
for (i = 0; i < entries; i++) {
|
|
|
|
pid_match = wwn_match = 0;
|
|
|
|
|
|
|
|
if (!(pri_entry->flags & FCP_PRIO_ENTRY_VALID)) {
|
|
|
|
pri_entry++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check source pid for a match */
|
|
|
|
if (pri_entry->flags & FCP_PRIO_ENTRY_SPID_VALID) {
|
|
|
|
pid1 = pri_entry->src_pid & INVALID_PORT_ID;
|
|
|
|
pid2 = vha->d_id.b24 & INVALID_PORT_ID;
|
|
|
|
if (pid1 == INVALID_PORT_ID)
|
|
|
|
pid_match++;
|
|
|
|
else if (pid1 == pid2)
|
|
|
|
pid_match++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check destination pid for a match */
|
|
|
|
if (pri_entry->flags & FCP_PRIO_ENTRY_DPID_VALID) {
|
|
|
|
pid1 = pri_entry->dst_pid & INVALID_PORT_ID;
|
|
|
|
pid2 = fcport->d_id.b24 & INVALID_PORT_ID;
|
|
|
|
if (pid1 == INVALID_PORT_ID)
|
|
|
|
pid_match++;
|
|
|
|
else if (pid1 == pid2)
|
|
|
|
pid_match++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check source WWN for a match */
|
|
|
|
if (pri_entry->flags & FCP_PRIO_ENTRY_SWWN_VALID) {
|
|
|
|
wwn1 = wwn_to_u64(vha->port_name);
|
|
|
|
wwn2 = wwn_to_u64(pri_entry->src_wwpn);
|
|
|
|
if (wwn2 == (uint64_t)-1)
|
|
|
|
wwn_match++;
|
|
|
|
else if (wwn1 == wwn2)
|
|
|
|
wwn_match++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check destination WWN for a match */
|
|
|
|
if (pri_entry->flags & FCP_PRIO_ENTRY_DWWN_VALID) {
|
|
|
|
wwn1 = wwn_to_u64(fcport->port_name);
|
|
|
|
wwn2 = wwn_to_u64(pri_entry->dst_wwpn);
|
|
|
|
if (wwn2 == (uint64_t)-1)
|
|
|
|
wwn_match++;
|
|
|
|
else if (wwn1 == wwn2)
|
|
|
|
wwn_match++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pid_match == 2 || wwn_match == 2) {
|
|
|
|
/* Found a matching entry */
|
|
|
|
if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID)
|
|
|
|
priority = pri_entry->tag;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pri_entry++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla24xx_update_fcport_fcp_prio
|
|
|
|
* Activates fcp priority for the logged in fc port
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
* fcp = port structure pointer.
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* QLA_SUCCESS or QLA_FUNCTION_FAILED
|
|
|
|
*
|
|
|
|
* Context:
|
|
|
|
* Kernel context.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *ha, fc_port_t *fcport)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
uint8_t priority;
|
|
|
|
uint16_t mb[5];
|
|
|
|
|
|
|
|
if (atomic_read(&fcport->state) == FCS_UNCONFIGURED ||
|
|
|
|
fcport->port_type != FCT_TARGET ||
|
|
|
|
fcport->loop_id == FC_NO_LOOP_ID)
|
|
|
|
return QLA_FUNCTION_FAILED;
|
|
|
|
|
|
|
|
priority = qla24xx_get_fcp_prio(ha, fcport);
|
|
|
|
ret = qla24xx_set_fcp_prio(ha, fcport->loop_id, priority, mb);
|
|
|
|
if (ret == QLA_SUCCESS)
|
|
|
|
fcport->fcp_prio = priority;
|
|
|
|
else
|
|
|
|
DEBUG2(printk(KERN_WARNING
|
|
|
|
"scsi(%ld): Unable to activate fcp priority, "
|
|
|
|
" ret=0x%x\n", ha->host_no, ret));
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qla24xx_update_all_fcp_prio
|
|
|
|
* Activates fcp priority for all the logged in ports
|
|
|
|
*
|
|
|
|
* Input:
|
|
|
|
* ha = adapter block pointer.
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* QLA_SUCCESS or QLA_FUNCTION_FAILED
|
|
|
|
*
|
|
|
|
* Context:
|
|
|
|
* Kernel context.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
qla24xx_update_all_fcp_prio(scsi_qla_host_t *vha)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
fc_port_t *fcport;
|
|
|
|
|
|
|
|
ret = QLA_FUNCTION_FAILED;
|
|
|
|
/* We need to set priority for all logged in ports */
|
|
|
|
list_for_each_entry(fcport, &vha->vp_fcports, list)
|
|
|
|
ret = qla24xx_update_fcport_fcp_prio(vha, fcport);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|