2010-04-12 17:59:55 -07:00
/*
* QLogic Fibre Channel HBA Driver
2011-03-30 11:46:23 -07:00
* Copyright ( c ) 2003 - 2011 QLogic Corporation
2010-04-12 17:59:55 -07:00
*
* See LICENSE . qla2xxx for copyright and licensing details .
*/
# include "qla_def.h"
# include <linux/delay.h>
# include <linux/pci.h>
2011-08-16 11:31:44 -07:00
# include <linux/ratelimit.h>
# include <linux/vmalloc.h>
2011-02-23 15:27:15 -08:00
# include <scsi/scsi_tcq.h>
2010-04-12 17:59:55 -07:00
# define MASK(n) ((1ULL<<(n))-1)
# define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \
( ( addr > > 25 ) & 0x3ff ) )
# define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | \
( ( addr > > 25 ) & 0x3ff ) )
# define MS_WIN(addr) (addr & 0x0ffc0000)
# define QLA82XX_PCI_MN_2M (0)
# define QLA82XX_PCI_MS_2M (0x80000)
# define QLA82XX_PCI_OCM0_2M (0xc0000)
# define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800)
# define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
2010-05-28 15:08:26 -07:00
# define BLOCK_PROTECT_BITS 0x0F
2010-04-12 17:59:55 -07:00
/* CRB window related */
# define CRB_BLK(off) ((off >> 20) & 0x3f)
# define CRB_SUBBLK(off) ((off >> 16) & 0xf)
# define CRB_WINDOW_2M (0x130060)
# define QLA82XX_PCI_CAMQM_2M_END (0x04800800UL)
# define CRB_HI(off) ((qla82xx_crb_hub_agt[CRB_BLK(off)] << 20) | \
( ( off ) & 0xf0000 ) )
# define QLA82XX_PCI_CAMQM_2M_BASE (0x000ff800UL)
# define CRB_INDIRECT_2M (0x1e0000UL)
# define MAX_CRB_XFORM 60
static unsigned long crb_addr_xform [ MAX_CRB_XFORM ] ;
int qla82xx_crb_table_initialized ;
# define qla82xx_crb_addr_transform(name) \
( crb_addr_xform [ QLA82XX_HW_PX_MAP_CRB_ # # name ] = \
QLA82XX_HW_CRB_HUB_AGT_ADR_ # # name < < 20 )
static void qla82xx_crb_addr_transform_setup ( void )
{
qla82xx_crb_addr_transform ( XDMA ) ;
qla82xx_crb_addr_transform ( TIMR ) ;
qla82xx_crb_addr_transform ( SRE ) ;
qla82xx_crb_addr_transform ( SQN3 ) ;
qla82xx_crb_addr_transform ( SQN2 ) ;
qla82xx_crb_addr_transform ( SQN1 ) ;
qla82xx_crb_addr_transform ( SQN0 ) ;
qla82xx_crb_addr_transform ( SQS3 ) ;
qla82xx_crb_addr_transform ( SQS2 ) ;
qla82xx_crb_addr_transform ( SQS1 ) ;
qla82xx_crb_addr_transform ( SQS0 ) ;
qla82xx_crb_addr_transform ( RPMX7 ) ;
qla82xx_crb_addr_transform ( RPMX6 ) ;
qla82xx_crb_addr_transform ( RPMX5 ) ;
qla82xx_crb_addr_transform ( RPMX4 ) ;
qla82xx_crb_addr_transform ( RPMX3 ) ;
qla82xx_crb_addr_transform ( RPMX2 ) ;
qla82xx_crb_addr_transform ( RPMX1 ) ;
qla82xx_crb_addr_transform ( RPMX0 ) ;
qla82xx_crb_addr_transform ( ROMUSB ) ;
qla82xx_crb_addr_transform ( SN ) ;
qla82xx_crb_addr_transform ( QMN ) ;
qla82xx_crb_addr_transform ( QMS ) ;
qla82xx_crb_addr_transform ( PGNI ) ;
qla82xx_crb_addr_transform ( PGND ) ;
qla82xx_crb_addr_transform ( PGN3 ) ;
qla82xx_crb_addr_transform ( PGN2 ) ;
qla82xx_crb_addr_transform ( PGN1 ) ;
qla82xx_crb_addr_transform ( PGN0 ) ;
qla82xx_crb_addr_transform ( PGSI ) ;
qla82xx_crb_addr_transform ( PGSD ) ;
qla82xx_crb_addr_transform ( PGS3 ) ;
qla82xx_crb_addr_transform ( PGS2 ) ;
qla82xx_crb_addr_transform ( PGS1 ) ;
qla82xx_crb_addr_transform ( PGS0 ) ;
qla82xx_crb_addr_transform ( PS ) ;
qla82xx_crb_addr_transform ( PH ) ;
qla82xx_crb_addr_transform ( NIU ) ;
qla82xx_crb_addr_transform ( I2Q ) ;
qla82xx_crb_addr_transform ( EG ) ;
qla82xx_crb_addr_transform ( MN ) ;
qla82xx_crb_addr_transform ( MS ) ;
qla82xx_crb_addr_transform ( CAS2 ) ;
qla82xx_crb_addr_transform ( CAS1 ) ;
qla82xx_crb_addr_transform ( CAS0 ) ;
qla82xx_crb_addr_transform ( CAM ) ;
qla82xx_crb_addr_transform ( C2C1 ) ;
qla82xx_crb_addr_transform ( C2C0 ) ;
qla82xx_crb_addr_transform ( SMB ) ;
qla82xx_crb_addr_transform ( OCM0 ) ;
/*
* Used only in P3 just define it for P2 also .
*/
qla82xx_crb_addr_transform ( I2C0 ) ;
qla82xx_crb_table_initialized = 1 ;
}
struct crb_128M_2M_block_map crb_128M_2M_map [ 64 ] = {
{ { { 0 , 0 , 0 , 0 } } } ,
{ { { 1 , 0x0100000 , 0x0102000 , 0x120000 } ,
{ 1 , 0x0110000 , 0x0120000 , 0x130000 } ,
{ 1 , 0x0120000 , 0x0122000 , 0x124000 } ,
{ 1 , 0x0130000 , 0x0132000 , 0x126000 } ,
{ 1 , 0x0140000 , 0x0142000 , 0x128000 } ,
{ 1 , 0x0150000 , 0x0152000 , 0x12a000 } ,
{ 1 , 0x0160000 , 0x0170000 , 0x110000 } ,
{ 1 , 0x0170000 , 0x0172000 , 0x12e000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 1 , 0x01e0000 , 0x01e0800 , 0x122000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } } } ,
{ { { 1 , 0x0200000 , 0x0210000 , 0x180000 } } } ,
{ { { 0 , 0 , 0 , 0 } } } ,
{ { { 1 , 0x0400000 , 0x0401000 , 0x169000 } } } ,
{ { { 1 , 0x0500000 , 0x0510000 , 0x140000 } } } ,
{ { { 1 , 0x0600000 , 0x0610000 , 0x1c0000 } } } ,
{ { { 1 , 0x0700000 , 0x0704000 , 0x1b8000 } } } ,
{ { { 1 , 0x0800000 , 0x0802000 , 0x170000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 1 , 0x08f0000 , 0x08f2000 , 0x172000 } } } ,
{ { { 1 , 0x0900000 , 0x0902000 , 0x174000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 1 , 0x09f0000 , 0x09f2000 , 0x176000 } } } ,
{ { { 0 , 0x0a00000 , 0x0a02000 , 0x178000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 1 , 0x0af0000 , 0x0af2000 , 0x17a000 } } } ,
{ { { 0 , 0x0b00000 , 0x0b02000 , 0x17c000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 1 , 0x0bf0000 , 0x0bf2000 , 0x17e000 } } } ,
{ { { 1 , 0x0c00000 , 0x0c04000 , 0x1d4000 } } } ,
{ { { 1 , 0x0d00000 , 0x0d04000 , 0x1a4000 } } } ,
{ { { 1 , 0x0e00000 , 0x0e04000 , 0x1a0000 } } } ,
{ { { 1 , 0x0f00000 , 0x0f01000 , 0x164000 } } } ,
{ { { 0 , 0x1000000 , 0x1004000 , 0x1a8000 } } } ,
{ { { 1 , 0x1100000 , 0x1101000 , 0x160000 } } } ,
{ { { 1 , 0x1200000 , 0x1201000 , 0x161000 } } } ,
{ { { 1 , 0x1300000 , 0x1301000 , 0x162000 } } } ,
{ { { 1 , 0x1400000 , 0x1401000 , 0x163000 } } } ,
{ { { 1 , 0x1500000 , 0x1501000 , 0x165000 } } } ,
{ { { 1 , 0x1600000 , 0x1601000 , 0x166000 } } } ,
{ { { 0 , 0 , 0 , 0 } } } ,
{ { { 0 , 0 , 0 , 0 } } } ,
{ { { 0 , 0 , 0 , 0 } } } ,
{ { { 0 , 0 , 0 , 0 } } } ,
{ { { 0 , 0 , 0 , 0 } } } ,
{ { { 0 , 0 , 0 , 0 } } } ,
{ { { 1 , 0x1d00000 , 0x1d10000 , 0x190000 } } } ,
{ { { 1 , 0x1e00000 , 0x1e01000 , 0x16a000 } } } ,
{ { { 1 , 0x1f00000 , 0x1f10000 , 0x150000 } } } ,
{ { { 0 } } } ,
{ { { 1 , 0x2100000 , 0x2102000 , 0x120000 } ,
{ 1 , 0x2110000 , 0x2120000 , 0x130000 } ,
{ 1 , 0x2120000 , 0x2122000 , 0x124000 } ,
{ 1 , 0x2130000 , 0x2132000 , 0x126000 } ,
{ 1 , 0x2140000 , 0x2142000 , 0x128000 } ,
{ 1 , 0x2150000 , 0x2152000 , 0x12a000 } ,
{ 1 , 0x2160000 , 0x2170000 , 0x110000 } ,
{ 1 , 0x2170000 , 0x2172000 , 0x12e000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } ,
{ 0 , 0x0000000 , 0x0000000 , 0x000000 } } } ,
{ { { 1 , 0x2200000 , 0x2204000 , 0x1b0000 } } } ,
{ { { 0 } } } ,
{ { { 0 } } } ,
{ { { 0 } } } ,
{ { { 0 } } } ,
{ { { 0 } } } ,
{ { { 1 , 0x2800000 , 0x2804000 , 0x1a4000 } } } ,
{ { { 1 , 0x2900000 , 0x2901000 , 0x16b000 } } } ,
{ { { 1 , 0x2a00000 , 0x2a00400 , 0x1ac400 } } } ,
{ { { 1 , 0x2b00000 , 0x2b00400 , 0x1ac800 } } } ,
{ { { 1 , 0x2c00000 , 0x2c00400 , 0x1acc00 } } } ,
{ { { 1 , 0x2d00000 , 0x2d00400 , 0x1ad000 } } } ,
{ { { 1 , 0x2e00000 , 0x2e00400 , 0x1ad400 } } } ,
{ { { 1 , 0x2f00000 , 0x2f00400 , 0x1ad800 } } } ,
{ { { 1 , 0x3000000 , 0x3000400 , 0x1adc00 } } } ,
{ { { 0 , 0x3100000 , 0x3104000 , 0x1a8000 } } } ,
{ { { 1 , 0x3200000 , 0x3204000 , 0x1d4000 } } } ,
{ { { 1 , 0x3300000 , 0x3304000 , 0x1a0000 } } } ,
{ { { 0 } } } ,
{ { { 1 , 0x3500000 , 0x3500400 , 0x1ac000 } } } ,
{ { { 1 , 0x3600000 , 0x3600400 , 0x1ae000 } } } ,
{ { { 1 , 0x3700000 , 0x3700400 , 0x1ae400 } } } ,
{ { { 1 , 0x3800000 , 0x3804000 , 0x1d0000 } } } ,
{ { { 1 , 0x3900000 , 0x3904000 , 0x1b4000 } } } ,
{ { { 1 , 0x3a00000 , 0x3a04000 , 0x1d8000 } } } ,
{ { { 0 } } } ,
{ { { 0 } } } ,
{ { { 1 , 0x3d00000 , 0x3d04000 , 0x1dc000 } } } ,
{ { { 1 , 0x3e00000 , 0x3e01000 , 0x167000 } } } ,
{ { { 1 , 0x3f00000 , 0x3f01000 , 0x168000 } } }
} ;
/*
* top 12 bits of crb internal address ( hub , agent )
*/
unsigned qla82xx_crb_hub_agt [ 64 ] = {
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PS ,
QLA82XX_HW_CRB_HUB_AGT_ADR_MN ,
QLA82XX_HW_CRB_HUB_AGT_ADR_MS ,
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_SRE ,
QLA82XX_HW_CRB_HUB_AGT_ADR_NIU ,
QLA82XX_HW_CRB_HUB_AGT_ADR_QMN ,
QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q ,
QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR ,
QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGND ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3 ,
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI ,
QLA82XX_HW_CRB_HUB_AGT_ADR_SN ,
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_EG ,
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PS ,
QLA82XX_HW_CRB_HUB_AGT_ADR_CAM ,
0 ,
0 ,
0 ,
0 ,
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR ,
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA ,
QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q ,
QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB ,
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0 ,
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_SMB ,
QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1 ,
0 ,
QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC ,
0 ,
} ;
2010-05-04 15:01:34 -07:00
/* Device states */
2011-08-16 11:31:44 -07:00
char * q_dev_state [ ] = {
2010-05-04 15:01:34 -07:00
" Unknown " ,
" Cold " ,
" Initializing " ,
" Ready " ,
" Need Reset " ,
" Need Quiescent " ,
" Failed " ,
" Quiescent " ,
} ;
2011-08-16 11:31:44 -07:00
char * qdev_state ( uint32_t dev_state )
{
return q_dev_state [ dev_state ] ;
}
2010-04-12 17:59:55 -07:00
/*
* In : ' off ' is offset from CRB space in 128 M pci map
* Out : ' off ' is 2 M pci map addr
* side effect : lock crb window
*/
static void
qla82xx_pci_set_crbwindow_2M ( struct qla_hw_data * ha , ulong * off )
{
u32 win_read ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
ha - > crb_win = CRB_HI ( * off ) ;
writel ( ha - > crb_win ,
( void * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ) ;
/* Read back value to make sure write has gone through before trying
* to use it .
*/
win_read = RD_REG_DWORD ( ( void * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ) ;
if ( win_read ! = ha - > crb_win ) {
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb000 ,
" %s: Written crbwin (0x%x) "
" != Read crbwin (0x%x), off=0x%lx. \n " ,
2011-11-18 09:03:06 -08:00
__func__ , ha - > crb_win , win_read , * off ) ;
2010-04-12 17:59:55 -07:00
}
* off = ( * off & MASK ( 16 ) ) + CRB_INDIRECT_2M + ha - > nx_pcibase ;
}
static inline unsigned long
qla82xx_pci_set_crbwindow ( struct qla_hw_data * ha , u64 off )
{
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
/* See if we are currently pointing to the region we want to use next */
if ( ( off > = QLA82XX_CRB_PCIX_HOST ) & & ( off < QLA82XX_CRB_DDR_NET ) ) {
/* No need to change window. PCIX and PCIEregs are in both
* regs are in both windows .
*/
return off ;
}
if ( ( off > = QLA82XX_CRB_PCIX_HOST ) & & ( off < QLA82XX_CRB_PCIX_HOST2 ) ) {
/* We are in first CRB window */
if ( ha - > curr_window ! = 0 )
WARN_ON ( 1 ) ;
return off ;
}
if ( ( off > QLA82XX_CRB_PCIX_HOST2 ) & & ( off < QLA82XX_CRB_MAX ) ) {
/* We are in second CRB window */
off = off - QLA82XX_CRB_PCIX_HOST2 + QLA82XX_CRB_PCIX_HOST ;
if ( ha - > curr_window ! = 1 )
return off ;
/* We are in the QM or direct access
* register region - do nothing
*/
if ( ( off > = QLA82XX_PCI_DIRECT_CRB ) & &
( off < QLA82XX_PCI_CAMQM_MAX ) )
return off ;
}
/* strange address given */
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb001 ,
2011-11-18 09:03:06 -08:00
" %s: Warning: unm_nic_pci_set_crbwindow "
2011-07-14 12:00:13 -07:00
" called with an unknown address(%llx). \n " ,
QLA2XXX_DRIVER_NAME , off ) ;
2010-04-12 17:59:55 -07:00
return off ;
}
2010-09-03 15:20:52 -07:00
static int
qla82xx_pci_get_crb_addr_2M ( struct qla_hw_data * ha , ulong * off )
{
struct crb_128M_2M_sub_block_map * m ;
if ( * off > = QLA82XX_CRB_MAX )
return - 1 ;
if ( * off > = QLA82XX_PCI_CAMQM & & ( * off < QLA82XX_PCI_CAMQM_2M_END ) ) {
* off = ( * off - QLA82XX_PCI_CAMQM ) +
QLA82XX_PCI_CAMQM_2M_BASE + ha - > nx_pcibase ;
return 0 ;
}
if ( * off < QLA82XX_PCI_CRBSPACE )
return - 1 ;
* off - = QLA82XX_PCI_CRBSPACE ;
/* Try direct map */
m = & crb_128M_2M_map [ CRB_BLK ( * off ) ] . sub_block [ CRB_SUBBLK ( * off ) ] ;
if ( m - > valid & & ( m - > start_128M < = * off ) & & ( m - > end_128M > * off ) ) {
* off = * off + m - > start_2M - m - > start_128M + ha - > nx_pcibase ;
return 0 ;
}
/* Not in direct map, use crb window */
return 1 ;
}
# define CRB_WIN_LOCK_TIMEOUT 100000000
static int qla82xx_crb_win_lock ( struct qla_hw_data * ha )
{
int done = 0 , timeout = 0 ;
while ( ! done ) {
/* acquire semaphore3 from PCI HW block */
done = qla82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM7_LOCK ) ) ;
if ( done = = 1 )
break ;
if ( timeout > = CRB_WIN_LOCK_TIMEOUT )
return - 1 ;
timeout + + ;
}
qla82xx_wr_32 ( ha , QLA82XX_CRB_WIN_LOCK_ID , ha - > portnum ) ;
return 0 ;
}
2010-04-12 17:59:55 -07:00
int
qla82xx_wr_32 ( struct qla_hw_data * ha , ulong off , u32 data )
{
unsigned long flags = 0 ;
int rv ;
rv = qla82xx_pci_get_crb_addr_2M ( ha , & off ) ;
BUG_ON ( rv = = - 1 ) ;
if ( rv = = 1 ) {
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
qla82xx_crb_win_lock ( ha ) ;
qla82xx_pci_set_crbwindow_2M ( ha , & off ) ;
}
writel ( data , ( void __iomem * ) off ) ;
if ( rv = = 1 ) {
qla82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM7_UNLOCK ) ) ;
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
}
return 0 ;
}
int
qla82xx_rd_32 ( struct qla_hw_data * ha , ulong off )
{
unsigned long flags = 0 ;
int rv ;
u32 data ;
rv = qla82xx_pci_get_crb_addr_2M ( ha , & off ) ;
BUG_ON ( rv = = - 1 ) ;
if ( rv = = 1 ) {
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
qla82xx_crb_win_lock ( ha ) ;
qla82xx_pci_set_crbwindow_2M ( ha , & off ) ;
}
data = RD_REG_DWORD ( ( void __iomem * ) off ) ;
if ( rv = = 1 ) {
qla82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM7_UNLOCK ) ) ;
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
}
return data ;
}
# define IDC_LOCK_TIMEOUT 100000000
int qla82xx_idc_lock ( struct qla_hw_data * ha )
{
int i ;
int done = 0 , timeout = 0 ;
while ( ! done ) {
/* acquire semaphore5 from PCI HW block */
done = qla82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM5_LOCK ) ) ;
if ( done = = 1 )
break ;
if ( timeout > = IDC_LOCK_TIMEOUT )
return - 1 ;
timeout + + ;
/* Yield CPU */
if ( ! in_interrupt ( ) )
schedule ( ) ;
else {
for ( i = 0 ; i < 20 ; i + + )
cpu_relax ( ) ;
}
}
return 0 ;
}
void qla82xx_idc_unlock ( struct qla_hw_data * ha )
{
qla82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM5_UNLOCK ) ) ;
}
/* PCI Windowing for DDR regions. */
# define QLA82XX_ADDR_IN_RANGE(addr, low, high) \
( ( ( addr ) < = ( high ) ) & & ( ( addr ) > = ( low ) ) )
/*
* check memory access boundary .
* used by test agent . support ddr access only for now
*/
static unsigned long
qla82xx_pci_mem_bound_check ( struct qla_hw_data * ha ,
unsigned long long addr , int size )
{
if ( ! QLA82XX_ADDR_IN_RANGE ( addr , QLA82XX_ADDR_DDR_NET ,
QLA82XX_ADDR_DDR_NET_MAX ) | |
! QLA82XX_ADDR_IN_RANGE ( addr + size - 1 , QLA82XX_ADDR_DDR_NET ,
QLA82XX_ADDR_DDR_NET_MAX ) | |
( ( size ! = 1 ) & & ( size ! = 2 ) & & ( size ! = 4 ) & & ( size ! = 8 ) ) )
return 0 ;
else
return 1 ;
}
int qla82xx_pci_set_window_warning_count ;
2010-09-03 15:20:52 -07:00
static unsigned long
2010-04-12 17:59:55 -07:00
qla82xx_pci_set_window ( struct qla_hw_data * ha , unsigned long long addr )
{
int window ;
u32 win_read ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
if ( QLA82XX_ADDR_IN_RANGE ( addr , QLA82XX_ADDR_DDR_NET ,
QLA82XX_ADDR_DDR_NET_MAX ) ) {
/* DDR network side */
window = MN_WIN ( addr ) ;
ha - > ddr_mn_window = window ;
qla82xx_wr_32 ( ha ,
ha - > mn_win_crb | QLA82XX_PCI_CRBSPACE , window ) ;
win_read = qla82xx_rd_32 ( ha ,
ha - > mn_win_crb | QLA82XX_PCI_CRBSPACE ) ;
if ( ( win_read < < 17 ) ! = window ) {
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb003 ,
" %s: Written MNwin (0x%x) != Read MNwin (0x%x). \n " ,
2010-04-12 17:59:55 -07:00
__func__ , window , win_read ) ;
}
addr = GET_MEM_OFFS_2M ( addr ) + QLA82XX_PCI_DDR_NET ;
} else if ( QLA82XX_ADDR_IN_RANGE ( addr , QLA82XX_ADDR_OCM0 ,
QLA82XX_ADDR_OCM0_MAX ) ) {
unsigned int temp1 ;
if ( ( addr & 0x00ff800 ) = = 0xff800 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb004 ,
2010-04-12 17:59:55 -07:00
" %s: QM access not handled. \n " , __func__ ) ;
addr = - 1UL ;
}
window = OCM_WIN ( addr ) ;
ha - > ddr_mn_window = window ;
qla82xx_wr_32 ( ha ,
ha - > mn_win_crb | QLA82XX_PCI_CRBSPACE , window ) ;
win_read = qla82xx_rd_32 ( ha ,
ha - > mn_win_crb | QLA82XX_PCI_CRBSPACE ) ;
temp1 = ( ( window & 0x1FF ) < < 7 ) |
( ( window & 0x0FFFE0000 ) > > 17 ) ;
if ( win_read ! = temp1 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb005 ,
" %s: Written OCMwin (0x%x) != Read OCMwin (0x%x). \n " ,
2010-04-12 17:59:55 -07:00
__func__ , temp1 , win_read ) ;
}
addr = GET_MEM_OFFS_2M ( addr ) + QLA82XX_PCI_OCM0_2M ;
} else if ( QLA82XX_ADDR_IN_RANGE ( addr , QLA82XX_ADDR_QDR_NET ,
QLA82XX_P3_ADDR_QDR_NET_MAX ) ) {
/* QDR network side */
window = MS_WIN ( addr ) ;
ha - > qdr_sn_window = window ;
qla82xx_wr_32 ( ha ,
ha - > ms_win_crb | QLA82XX_PCI_CRBSPACE , window ) ;
win_read = qla82xx_rd_32 ( ha ,
ha - > ms_win_crb | QLA82XX_PCI_CRBSPACE ) ;
if ( win_read ! = window ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb006 ,
" %s: Written MSwin (0x%x) != Read MSwin (0x%x). \n " ,
2010-04-12 17:59:55 -07:00
__func__ , window , win_read ) ;
}
addr = GET_MEM_OFFS_2M ( addr ) + QLA82XX_PCI_QDR_NET ;
} else {
/*
* peg gdb frequently accesses memory that doesn ' t exist ,
* this limits the chit chat so debugging isn ' t slowed down .
*/
if ( ( qla82xx_pci_set_window_warning_count + + < 8 ) | |
( qla82xx_pci_set_window_warning_count % 64 = = 0 ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb007 ,
" %s: Warning:%s Unknown address range!. \n " ,
__func__ , QLA2XXX_DRIVER_NAME ) ;
2010-04-12 17:59:55 -07:00
}
addr = - 1UL ;
}
return addr ;
}
/* check if address is in the same windows as the previous access */
static int qla82xx_pci_is_same_window ( struct qla_hw_data * ha ,
unsigned long long addr )
{
int window ;
unsigned long long qdr_max ;
qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX ;
/* DDR network side */
if ( QLA82XX_ADDR_IN_RANGE ( addr , QLA82XX_ADDR_DDR_NET ,
QLA82XX_ADDR_DDR_NET_MAX ) )
BUG ( ) ;
else if ( QLA82XX_ADDR_IN_RANGE ( addr , QLA82XX_ADDR_OCM0 ,
QLA82XX_ADDR_OCM0_MAX ) )
return 1 ;
else if ( QLA82XX_ADDR_IN_RANGE ( addr , QLA82XX_ADDR_OCM1 ,
QLA82XX_ADDR_OCM1_MAX ) )
return 1 ;
else if ( QLA82XX_ADDR_IN_RANGE ( addr , QLA82XX_ADDR_QDR_NET , qdr_max ) ) {
/* QDR network side */
window = ( ( addr - QLA82XX_ADDR_QDR_NET ) > > 22 ) & 0x3f ;
if ( ha - > qdr_sn_window = = window )
return 1 ;
}
return 0 ;
}
static int qla82xx_pci_mem_read_direct ( struct qla_hw_data * ha ,
u64 off , void * data , int size )
{
unsigned long flags ;
2010-05-04 15:01:34 -07:00
void * addr = NULL ;
2010-04-12 17:59:55 -07:00
int ret = 0 ;
u64 start ;
uint8_t * mem_ptr = NULL ;
unsigned long mem_base ;
unsigned long mem_page ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
/*
* If attempting to access unknown address or straddle hw windows ,
* do not access .
*/
start = qla82xx_pci_set_window ( ha , off ) ;
if ( ( start = = - 1UL ) | |
( qla82xx_pci_is_same_window ( ha , off + size - 1 ) = = 0 ) ) {
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0xb008 ,
" %s out of bound pci memory "
" access, offset is 0x%llx. \n " ,
QLA2XXX_DRIVER_NAME , off ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
2010-05-04 15:01:34 -07:00
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
mem_base = pci_resource_start ( ha - > pdev , 0 ) ;
mem_page = start & PAGE_MASK ;
/* Map two pages whenever user tries to access addresses in two
* consecutive pages .
*/
if ( mem_page ! = ( ( start + size - 1 ) & PAGE_MASK ) )
mem_ptr = ioremap ( mem_base + mem_page , PAGE_SIZE * 2 ) ;
else
mem_ptr = ioremap ( mem_base + mem_page , PAGE_SIZE ) ;
if ( mem_ptr = = 0UL ) {
* ( u8 * ) data = 0 ;
return - 1 ;
2010-04-12 17:59:55 -07:00
}
2010-05-04 15:01:34 -07:00
addr = mem_ptr ;
addr + = start & ( PAGE_SIZE - 1 ) ;
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
2010-04-12 17:59:55 -07:00
switch ( size ) {
case 1 :
* ( u8 * ) data = readb ( addr ) ;
break ;
case 2 :
* ( u16 * ) data = readw ( addr ) ;
break ;
case 4 :
* ( u32 * ) data = readl ( addr ) ;
break ;
case 8 :
* ( u64 * ) data = readq ( addr ) ;
break ;
default :
ret = - 1 ;
break ;
}
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
if ( mem_ptr )
iounmap ( mem_ptr ) ;
return ret ;
}
static int
qla82xx_pci_mem_write_direct ( struct qla_hw_data * ha ,
u64 off , void * data , int size )
{
unsigned long flags ;
2010-05-04 15:01:34 -07:00
void * addr = NULL ;
2010-04-12 17:59:55 -07:00
int ret = 0 ;
u64 start ;
uint8_t * mem_ptr = NULL ;
unsigned long mem_base ;
unsigned long mem_page ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
/*
* If attempting to access unknown address or straddle hw windows ,
* do not access .
*/
start = qla82xx_pci_set_window ( ha , off ) ;
if ( ( start = = - 1UL ) | |
( qla82xx_pci_is_same_window ( ha , off + size - 1 ) = = 0 ) ) {
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0xb009 ,
" %s out of bount memory "
" access, offset is 0x%llx. \n " ,
QLA2XXX_DRIVER_NAME , off ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
2010-05-04 15:01:34 -07:00
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
mem_base = pci_resource_start ( ha - > pdev , 0 ) ;
mem_page = start & PAGE_MASK ;
/* Map two pages whenever user tries to access addresses in two
* consecutive pages .
*/
if ( mem_page ! = ( ( start + size - 1 ) & PAGE_MASK ) )
mem_ptr = ioremap ( mem_base + mem_page , PAGE_SIZE * 2 ) ;
else
mem_ptr = ioremap ( mem_base + mem_page , PAGE_SIZE ) ;
if ( mem_ptr = = 0UL )
return - 1 ;
2010-04-12 17:59:55 -07:00
2010-05-04 15:01:34 -07:00
addr = mem_ptr ;
addr + = start & ( PAGE_SIZE - 1 ) ;
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
2010-04-12 17:59:55 -07:00
switch ( size ) {
case 1 :
writeb ( * ( u8 * ) data , addr ) ;
break ;
case 2 :
writew ( * ( u16 * ) data , addr ) ;
break ;
case 4 :
writel ( * ( u32 * ) data , addr ) ;
break ;
case 8 :
writeq ( * ( u64 * ) data , addr ) ;
break ;
default :
ret = - 1 ;
break ;
}
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
if ( mem_ptr )
iounmap ( mem_ptr ) ;
return ret ;
}
# define MTU_FUDGE_FACTOR 100
2010-09-03 15:20:52 -07:00
static unsigned long
qla82xx_decode_crb_addr ( unsigned long addr )
2010-04-12 17:59:55 -07:00
{
int i ;
unsigned long base_addr , offset , pci_base ;
if ( ! qla82xx_crb_table_initialized )
qla82xx_crb_addr_transform_setup ( ) ;
pci_base = ADDR_ERROR ;
base_addr = addr & 0xfff00000 ;
offset = addr & 0x000fffff ;
for ( i = 0 ; i < MAX_CRB_XFORM ; i + + ) {
if ( crb_addr_xform [ i ] = = base_addr ) {
pci_base = i < < 20 ;
break ;
}
}
if ( pci_base = = ADDR_ERROR )
return pci_base ;
return pci_base + offset ;
}
static long rom_max_timeout = 100 ;
static long qla82xx_rom_lock_timeout = 100 ;
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_rom_lock ( struct qla_hw_data * ha )
{
int done = 0 , timeout = 0 ;
while ( ! done ) {
/* acquire semaphore2 from PCI HW block */
done = qla82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM2_LOCK ) ) ;
if ( done = = 1 )
break ;
if ( timeout > = qla82xx_rom_lock_timeout )
return - 1 ;
timeout + + ;
}
qla82xx_wr_32 ( ha , QLA82XX_ROM_LOCK_ID , ROM_LOCK_DRIVER ) ;
return 0 ;
}
2011-05-10 11:30:10 -07:00
static void
qla82xx_rom_unlock ( struct qla_hw_data * ha )
{
qla82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM2_UNLOCK ) ) ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_wait_rom_busy ( struct qla_hw_data * ha )
{
long timeout = 0 ;
long done = 0 ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
while ( done = = 0 ) {
done = qla82xx_rd_32 ( ha , QLA82XX_ROMUSB_GLB_STATUS ) ;
done & = 4 ;
timeout + + ;
if ( timeout > = rom_max_timeout ) {
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb00a ,
" %s: Timeout reached waiting for rom busy. \n " ,
QLA2XXX_DRIVER_NAME ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
}
return 0 ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_wait_rom_done ( struct qla_hw_data * ha )
{
long timeout = 0 ;
long done = 0 ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
while ( done = = 0 ) {
done = qla82xx_rd_32 ( ha , QLA82XX_ROMUSB_GLB_STATUS ) ;
done & = 2 ;
timeout + + ;
if ( timeout > = rom_max_timeout ) {
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb00b ,
" %s: Timeout reached waiting for rom done. \n " ,
QLA2XXX_DRIVER_NAME ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
}
return 0 ;
}
2012-02-09 11:15:41 -08:00
int
qla82xx_md_rw_32 ( struct qla_hw_data * ha , uint32_t off , u32 data , uint8_t flag )
{
uint32_t off_value , rval = 0 ;
WRT_REG_DWORD ( ( void * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ,
( off & 0xFFFF0000 ) ) ;
/* Read back value to make sure write has gone through */
RD_REG_DWORD ( ( void * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ) ;
off_value = ( off & 0x0000FFFF ) ;
if ( flag )
WRT_REG_DWORD ( ( void * )
( off_value + CRB_INDIRECT_2M + ha - > nx_pcibase ) ,
data ) ;
else
rval = RD_REG_DWORD ( ( void * )
( off_value + CRB_INDIRECT_2M + ha - > nx_pcibase ) ) ;
return rval ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_do_rom_fast_read ( struct qla_hw_data * ha , int addr , int * valp )
{
2012-02-09 11:15:41 -08:00
/* Dword reads to flash. */
qla82xx_md_rw_32 ( ha , MD_DIRECT_ROM_WINDOW , ( addr & 0xFFFF0000 ) , 1 ) ;
* valp = qla82xx_md_rw_32 ( ha , MD_DIRECT_ROM_READ_BASE +
( addr & 0x0000FFFF ) , 0 , 0 ) ;
2011-07-14 12:00:13 -07:00
2010-04-12 17:59:55 -07:00
return 0 ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_rom_fast_read ( struct qla_hw_data * ha , int addr , int * valp )
{
int ret , loops = 0 ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
while ( ( qla82xx_rom_lock ( ha ) ! = 0 ) & & ( loops < 50000 ) ) {
udelay ( 100 ) ;
schedule ( ) ;
loops + + ;
}
if ( loops > = 50000 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00b9 ,
" Failed to aquire SEM2 lock. \n " ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
ret = qla82xx_do_rom_fast_read ( ha , addr , valp ) ;
2011-05-10 11:30:10 -07:00
qla82xx_rom_unlock ( ha ) ;
2010-04-12 17:59:55 -07:00
return ret ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_read_status_reg ( struct qla_hw_data * ha , uint32_t * val )
{
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_INSTR_OPCODE , M25P_INSTR_RDSR ) ;
qla82xx_wait_rom_busy ( ha ) ;
if ( qla82xx_wait_rom_done ( ha ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb00c ,
" Error waiting for rom done. \n " ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
* val = qla82xx_rd_32 ( ha , QLA82XX_ROMUSB_ROM_RDATA ) ;
return 0 ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_flash_wait_write_finish ( struct qla_hw_data * ha )
{
long timeout = 0 ;
uint32_t done = 1 ;
uint32_t val ;
int ret = 0 ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_ABYTE_CNT , 0 ) ;
while ( ( done ! = 0 ) & & ( ret = = 0 ) ) {
ret = qla82xx_read_status_reg ( ha , & val ) ;
done = val & 1 ;
timeout + + ;
udelay ( 10 ) ;
cond_resched ( ) ;
if ( timeout > = 50000 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb00d ,
" Timeout reached waiting for write finish. \n " ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
}
return ret ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_flash_set_write_enable ( struct qla_hw_data * ha )
{
uint32_t val ;
qla82xx_wait_rom_busy ( ha ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_ABYTE_CNT , 0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_INSTR_OPCODE , M25P_INSTR_WREN ) ;
qla82xx_wait_rom_busy ( ha ) ;
if ( qla82xx_wait_rom_done ( ha ) )
return - 1 ;
if ( qla82xx_read_status_reg ( ha , & val ) ! = 0 )
return - 1 ;
if ( ( val & 2 ) ! = 2 )
return - 1 ;
return 0 ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_write_status_reg ( struct qla_hw_data * ha , uint32_t val )
{
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
if ( qla82xx_flash_set_write_enable ( ha ) )
return - 1 ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_WDATA , val ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_INSTR_OPCODE , 0x1 ) ;
if ( qla82xx_wait_rom_done ( ha ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb00e ,
" Error waiting for rom done. \n " ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
return qla82xx_flash_wait_write_finish ( ha ) ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_write_disable_flash ( struct qla_hw_data * ha )
{
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_INSTR_OPCODE , M25P_INSTR_WRDI ) ;
if ( qla82xx_wait_rom_done ( ha ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb00f ,
" Error waiting for rom done. \n " ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
return 0 ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
ql82xx_rom_lock_d ( struct qla_hw_data * ha )
{
int loops = 0 ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
while ( ( qla82xx_rom_lock ( ha ) ! = 0 ) & & ( loops < 50000 ) ) {
udelay ( 100 ) ;
cond_resched ( ) ;
loops + + ;
}
if ( loops > = 50000 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb010 ,
" ROM lock failed. \n " ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
2011-11-20 22:34:15 +01:00
return 0 ;
2010-04-12 17:59:55 -07:00
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_write_flash_dword ( struct qla_hw_data * ha , uint32_t flashaddr ,
uint32_t data )
{
int ret = 0 ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
ret = ql82xx_rom_lock_d ( ha ) ;
if ( ret < 0 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb011 ,
" ROM lock failed. \n " ) ;
2010-04-12 17:59:55 -07:00
return ret ;
}
if ( qla82xx_flash_set_write_enable ( ha ) )
goto done_write ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_WDATA , data ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_ADDRESS , flashaddr ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_ABYTE_CNT , 3 ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_INSTR_OPCODE , M25P_INSTR_PP ) ;
qla82xx_wait_rom_busy ( ha ) ;
if ( qla82xx_wait_rom_done ( ha ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb012 ,
" Error waiting for rom done. \n " ) ;
2010-04-12 17:59:55 -07:00
ret = - 1 ;
goto done_write ;
}
ret = qla82xx_flash_wait_write_finish ( ha ) ;
done_write :
2011-05-10 11:30:10 -07:00
qla82xx_rom_unlock ( ha ) ;
2010-04-12 17:59:55 -07:00
return ret ;
}
/* This routine does CRB initialize sequence
* to put the ISP into operational state
*/
2010-09-03 15:20:52 -07:00
static int
qla82xx_pinit_from_rom ( scsi_qla_host_t * vha )
2010-04-12 17:59:55 -07:00
{
int addr , val ;
int i ;
struct crb_addr_pair * buf ;
unsigned long off ;
unsigned offset , n ;
struct qla_hw_data * ha = vha - > hw ;
struct crb_addr_pair {
long addr ;
long data ;
} ;
/* Halt all the indiviual PEGs and other blocks of the ISP */
qla82xx_rom_lock ( ha ) ;
2010-12-21 16:00:19 -08:00
2011-03-30 11:46:24 -07:00
/* disable all I2Q */
qla82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x10 , 0x0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x14 , 0x0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x18 , 0x0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x1c , 0x0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x20 , 0x0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x24 , 0x0 ) ;
/* disable all niu interrupts */
2010-12-21 16:00:19 -08:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0x40 , 0xff ) ;
/* disable xge rx/tx */
qla82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0x70000 , 0x00 ) ;
/* disable xg1 rx/tx */
qla82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0x80000 , 0x00 ) ;
2011-03-30 11:46:24 -07:00
/* disable sideband mac */
qla82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0x90000 , 0x00 ) ;
/* disable ap0 mac */
qla82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0xa0000 , 0x00 ) ;
/* disable ap1 mac */
qla82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0xb0000 , 0x00 ) ;
2010-12-21 16:00:19 -08:00
/* halt sre */
val = qla82xx_rd_32 ( ha , QLA82XX_CRB_SRE + 0x1000 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_SRE + 0x1000 , val & ( ~ ( 0x1 ) ) ) ;
/* halt epg */
qla82xx_wr_32 ( ha , QLA82XX_CRB_EPG + 0x1300 , 0x1 ) ;
/* halt timers */
qla82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x0 , 0x0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x8 , 0x0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x10 , 0x0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x18 , 0x0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x100 , 0x0 ) ;
2011-03-30 11:46:24 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x200 , 0x0 ) ;
2010-12-21 16:00:19 -08:00
/* halt pegs */
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_0 + 0x3c , 1 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_1 + 0x3c , 1 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_2 + 0x3c , 1 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_3 + 0x3c , 1 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_4 + 0x3c , 1 ) ;
2011-03-30 11:46:24 -07:00
msleep ( 20 ) ;
2010-12-21 16:00:19 -08:00
/* big hammer */
2010-04-12 17:59:55 -07:00
if ( test_bit ( ABORT_ISP_ACTIVE , & vha - > dpc_flags ) )
/* don't reset CAM block on reset */
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET , 0xfeffffff ) ;
else
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET , 0xffffffff ) ;
2011-05-10 11:30:10 -07:00
qla82xx_rom_unlock ( ha ) ;
2010-04-12 17:59:55 -07:00
/* Read the signature value from the flash.
* Offset 0 : Contain signature ( 0xcafecafe )
* Offset 4 : Offset and number of addr / value pairs
* that present in CRB initialize sequence
*/
if ( qla82xx_rom_fast_read ( ha , 0 , & n ) ! = 0 | | n ! = 0xcafecafeUL | |
qla82xx_rom_fast_read ( ha , 4 , & n ) ! = 0 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x006e ,
" Error Reading crb_init area: n: %08x. \n " , n ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
/* Offset in flash = lower 16 bits
* Number of enteries = upper 16 bits
*/
offset = n & 0xffffU ;
n = ( n > > 16 ) & 0xffffU ;
/* number of addr/value pair should not exceed 1024 enteries */
if ( n > = 1024 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x0071 ,
" Card flash not initialized:n=0x%x. \n " , n ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x0072 ,
" %d CRB init values found in ROM. \n " , n ) ;
2010-04-12 17:59:55 -07:00
buf = kmalloc ( n * sizeof ( struct crb_addr_pair ) , GFP_KERNEL ) ;
if ( buf = = NULL ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x010c ,
" Unable to allocate memory. \n " ) ;
2010-04-12 17:59:55 -07:00
return - 1 ;
}
for ( i = 0 ; i < n ; i + + ) {
if ( qla82xx_rom_fast_read ( ha , 8 * i + 4 * offset , & val ) ! = 0 | |
qla82xx_rom_fast_read ( ha , 8 * i + 4 * offset + 4 , & addr ) ! = 0 ) {
kfree ( buf ) ;
return - 1 ;
}
buf [ i ] . addr = addr ;
buf [ i ] . data = val ;
}
for ( i = 0 ; i < n ; i + + ) {
/* Translate internal CRB initialization
* address to PCI bus address
*/
off = qla82xx_decode_crb_addr ( ( unsigned long ) buf [ i ] . addr ) +
QLA82XX_PCI_CRBSPACE ;
/* Not all CRB addr/value pair to be written,
* some of them are skipped
*/
/* skipping cold reboot MAGIC */
if ( off = = QLA82XX_CAM_RAM ( 0x1fc ) )
continue ;
/* do not reset PCI */
if ( off = = ( ROMUSB_GLB + 0xbc ) )
continue ;
/* skip core clock, so that firmware can increase the clock */
if ( off = = ( ROMUSB_GLB + 0xc8 ) )
continue ;
/* skip the function enable register */
if ( off = = QLA82XX_PCIE_REG ( PCIE_SETUP_FUNCTION ) )
continue ;
if ( off = = QLA82XX_PCIE_REG ( PCIE_SETUP_FUNCTION2 ) )
continue ;
if ( ( off & 0x0ff00000 ) = = QLA82XX_CRB_SMB )
continue ;
if ( ( off & 0x0ff00000 ) = = QLA82XX_CRB_DDR_NET )
continue ;
if ( off = = ADDR_ERROR ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x0116 ,
" Unknow addr: 0x%08lx. \n " , buf [ i ] . addr ) ;
2010-04-12 17:59:55 -07:00
continue ;
}
qla82xx_wr_32 ( ha , off , buf [ i ] . data ) ;
/* ISP requires much bigger delay to settle down,
* else crb_window returns 0xffffffff
*/
if ( off = = QLA82XX_ROMUSB_GLB_SW_RESET )
msleep ( 1000 ) ;
/* ISP requires millisec delay between
* successive CRB register updation
*/
msleep ( 1 ) ;
}
kfree ( buf ) ;
/* Resetting the data and instruction cache */
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_D + 0xec , 0x1e ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_D + 0x4c , 8 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_I + 0x4c , 8 ) ;
/* Clear all protocol processing engines */
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_0 + 0x8 , 0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_0 + 0xc , 0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_1 + 0x8 , 0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_1 + 0xc , 0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_2 + 0x8 , 0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_2 + 0xc , 0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_3 + 0x8 , 0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_3 + 0xc , 0 ) ;
return 0 ;
}
2010-09-03 15:20:52 -07:00
static int
qla82xx_pci_mem_write_2M ( struct qla_hw_data * ha ,
u64 off , void * data , int size )
{
int i , j , ret = 0 , loop , sz [ 2 ] , off0 ;
int scale , shift_amount , startword ;
uint32_t temp ;
uint64_t off8 , mem_crb , tmpw , word [ 2 ] = { 0 , 0 } ;
/*
* If not MN , go check for MS or invalid .
*/
if ( off > = QLA82XX_ADDR_QDR_NET & & off < = QLA82XX_P3_ADDR_QDR_NET_MAX )
mem_crb = QLA82XX_CRB_QDR_NET ;
else {
mem_crb = QLA82XX_CRB_DDR_NET ;
if ( qla82xx_pci_mem_bound_check ( ha , off , size ) = = 0 )
return qla82xx_pci_mem_write_direct ( ha ,
off , data , size ) ;
}
off0 = off & 0x7 ;
sz [ 0 ] = ( size < ( 8 - off0 ) ) ? size : ( 8 - off0 ) ;
sz [ 1 ] = size - sz [ 0 ] ;
off8 = off & 0xfffffff0 ;
loop = ( ( ( off & 0xf ) + size - 1 ) > > 4 ) + 1 ;
shift_amount = 4 ;
scale = 2 ;
startword = ( off & 0xf ) / 8 ;
for ( i = 0 ; i < loop ; i + + ) {
if ( qla82xx_pci_mem_read_2M ( ha , off8 +
( i < < shift_amount ) , & word [ i * scale ] , 8 ) )
return - 1 ;
}
switch ( size ) {
case 1 :
tmpw = * ( ( uint8_t * ) data ) ;
break ;
case 2 :
tmpw = * ( ( uint16_t * ) data ) ;
break ;
case 4 :
tmpw = * ( ( uint32_t * ) data ) ;
break ;
case 8 :
default :
tmpw = * ( ( uint64_t * ) data ) ;
break ;
}
if ( sz [ 0 ] = = 8 ) {
word [ startword ] = tmpw ;
} else {
word [ startword ] & =
~ ( ( ~ ( ~ 0ULL < < ( sz [ 0 ] * 8 ) ) ) < < ( off0 * 8 ) ) ;
word [ startword ] | = tmpw < < ( off0 * 8 ) ;
}
if ( sz [ 1 ] ! = 0 ) {
word [ startword + 1 ] & = ~ ( ~ 0ULL < < ( sz [ 1 ] * 8 ) ) ;
word [ startword + 1 ] | = tmpw > > ( sz [ 0 ] * 8 ) ;
}
for ( i = 0 ; i < loop ; i + + ) {
temp = off8 + ( i < < shift_amount ) ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_ADDR_LO , temp ) ;
temp = 0 ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_ADDR_HI , temp ) ;
temp = word [ i * scale ] & 0xffffffff ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_WRDATA_LO , temp ) ;
temp = ( word [ i * scale ] > > 32 ) & 0xffffffff ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_WRDATA_HI , temp ) ;
temp = word [ i * scale + 1 ] & 0xffffffff ;
qla82xx_wr_32 ( ha , mem_crb +
MIU_TEST_AGT_WRDATA_UPPER_LO , temp ) ;
temp = ( word [ i * scale + 1 ] > > 32 ) & 0xffffffff ;
qla82xx_wr_32 ( ha , mem_crb +
MIU_TEST_AGT_WRDATA_UPPER_HI , temp ) ;
temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL , temp ) ;
temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL , temp ) ;
for ( j = 0 ; j < MAX_CTL_CHECK ; j + + ) {
temp = qla82xx_rd_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL ) ;
if ( ( temp & MIU_TA_CTL_BUSY ) = = 0 )
break ;
}
if ( j > = MAX_CTL_CHECK ) {
if ( printk_ratelimit ( ) )
dev_err ( & ha - > pdev - > dev ,
2011-07-14 12:00:13 -07:00
" failed to write through agent. \n " ) ;
2010-09-03 15:20:52 -07:00
ret = - 1 ;
break ;
}
}
return ret ;
}
static int
2010-04-12 17:59:55 -07:00
qla82xx_fw_load_from_flash ( struct qla_hw_data * ha )
{
int i ;
long size = 0 ;
2010-05-28 15:08:23 -07:00
long flashaddr = ha - > flt_region_bootload < < 2 ;
long memaddr = BOOTLD_START ;
2010-04-12 17:59:55 -07:00
u64 data ;
u32 high , low ;
size = ( IMAGE_START - BOOTLD_START ) / 8 ;
for ( i = 0 ; i < size ; i + + ) {
if ( ( qla82xx_rom_fast_read ( ha , flashaddr , ( int * ) & low ) ) | |
( qla82xx_rom_fast_read ( ha , flashaddr + 4 , ( int * ) & high ) ) ) {
return - 1 ;
}
data = ( ( u64 ) high < < 32 ) | low ;
qla82xx_pci_mem_write_2M ( ha , memaddr , & data , 8 ) ;
flashaddr + = 8 ;
memaddr + = 8 ;
if ( i % 0x1000 = = 0 )
msleep ( 1 ) ;
}
udelay ( 100 ) ;
read_lock ( & ha - > hw_lock ) ;
2010-07-23 15:28:34 +05:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_0 + 0x18 , 0x1020 ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET , 0x80001e ) ;
2010-04-12 17:59:55 -07:00
read_unlock ( & ha - > hw_lock ) ;
return 0 ;
}
int
qla82xx_pci_mem_read_2M ( struct qla_hw_data * ha ,
u64 off , void * data , int size )
{
int i , j = 0 , k , start , end , loop , sz [ 2 ] , off0 [ 2 ] ;
int shift_amount ;
uint32_t temp ;
uint64_t off8 , val , mem_crb , word [ 2 ] = { 0 , 0 } ;
/*
* If not MN , go check for MS or invalid .
*/
if ( off > = QLA82XX_ADDR_QDR_NET & & off < = QLA82XX_P3_ADDR_QDR_NET_MAX )
mem_crb = QLA82XX_CRB_QDR_NET ;
else {
mem_crb = QLA82XX_CRB_DDR_NET ;
if ( qla82xx_pci_mem_bound_check ( ha , off , size ) = = 0 )
return qla82xx_pci_mem_read_direct ( ha ,
off , data , size ) ;
}
2010-07-23 15:28:34 +05:00
off8 = off & 0xfffffff0 ;
off0 [ 0 ] = off & 0xf ;
sz [ 0 ] = ( size < ( 16 - off0 [ 0 ] ) ) ? size : ( 16 - off0 [ 0 ] ) ;
shift_amount = 4 ;
2010-04-12 17:59:55 -07:00
loop = ( ( off0 [ 0 ] + size - 1 ) > > shift_amount ) + 1 ;
off0 [ 1 ] = 0 ;
sz [ 1 ] = size - sz [ 0 ] ;
for ( i = 0 ; i < loop ; i + + ) {
temp = off8 + ( i < < shift_amount ) ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_ADDR_LO , temp ) ;
temp = 0 ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_ADDR_HI , temp ) ;
temp = MIU_TA_CTL_ENABLE ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL , temp ) ;
temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE ;
qla82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL , temp ) ;
for ( j = 0 ; j < MAX_CTL_CHECK ; j + + ) {
temp = qla82xx_rd_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL ) ;
if ( ( temp & MIU_TA_CTL_BUSY ) = = 0 )
break ;
}
if ( j > = MAX_CTL_CHECK ) {
if ( printk_ratelimit ( ) )
dev_err ( & ha - > pdev - > dev ,
2011-07-14 12:00:13 -07:00
" failed to read through agent. \n " ) ;
2010-04-12 17:59:55 -07:00
break ;
}
start = off0 [ i ] > > 2 ;
end = ( off0 [ i ] + sz [ i ] - 1 ) > > 2 ;
for ( k = start ; k < = end ; k + + ) {
temp = qla82xx_rd_32 ( ha ,
mem_crb + MIU_TEST_AGT_RDDATA ( k ) ) ;
word [ i ] | = ( ( uint64_t ) temp < < ( 32 * ( k & 1 ) ) ) ;
}
}
if ( j > = MAX_CTL_CHECK )
return - 1 ;
if ( ( off0 [ 0 ] & 7 ) = = 0 ) {
val = word [ 0 ] ;
} else {
val = ( ( word [ 0 ] > > ( off0 [ 0 ] * 8 ) ) & ( ~ ( ~ 0ULL < < ( sz [ 0 ] * 8 ) ) ) ) |
( ( word [ 1 ] & ( ~ ( ~ 0ULL < < ( sz [ 1 ] * 8 ) ) ) ) < < ( sz [ 0 ] * 8 ) ) ;
}
switch ( size ) {
case 1 :
* ( uint8_t * ) data = val ;
break ;
case 2 :
* ( uint16_t * ) data = val ;
break ;
case 4 :
* ( uint32_t * ) data = val ;
break ;
case 8 :
* ( uint64_t * ) data = val ;
break ;
}
return 0 ;
}
2010-05-28 15:08:23 -07:00
static struct qla82xx_uri_table_desc *
qla82xx_get_table_desc ( const u8 * unirom , int section )
{
uint32_t i ;
struct qla82xx_uri_table_desc * directory =
( struct qla82xx_uri_table_desc * ) & unirom [ 0 ] ;
__le32 offset ;
__le32 tab_type ;
__le32 entries = cpu_to_le32 ( directory - > num_entries ) ;
for ( i = 0 ; i < entries ; i + + ) {
offset = cpu_to_le32 ( directory - > findex ) +
( i * cpu_to_le32 ( directory - > entry_size ) ) ;
tab_type = cpu_to_le32 ( * ( ( u32 * ) & unirom [ offset ] + 8 ) ) ;
if ( tab_type = = section )
return ( struct qla82xx_uri_table_desc * ) & unirom [ offset ] ;
}
return NULL ;
}
static struct qla82xx_uri_data_desc *
qla82xx_get_data_desc ( struct qla_hw_data * ha ,
u32 section , u32 idx_offset )
{
const u8 * unirom = ha - > hablob - > fw - > data ;
int idx = cpu_to_le32 ( * ( ( int * ) & unirom [ ha - > file_prd_off ] + idx_offset ) ) ;
struct qla82xx_uri_table_desc * tab_desc = NULL ;
__le32 offset ;
tab_desc = qla82xx_get_table_desc ( unirom , section ) ;
if ( ! tab_desc )
return NULL ;
offset = cpu_to_le32 ( tab_desc - > findex ) +
( cpu_to_le32 ( tab_desc - > entry_size ) * idx ) ;
return ( struct qla82xx_uri_data_desc * ) & unirom [ offset ] ;
}
static u8 *
qla82xx_get_bootld_offset ( struct qla_hw_data * ha )
{
u32 offset = BOOTLD_START ;
struct qla82xx_uri_data_desc * uri_desc = NULL ;
if ( ha - > fw_type = = QLA82XX_UNIFIED_ROMIMAGE ) {
uri_desc = qla82xx_get_data_desc ( ha ,
QLA82XX_URI_DIR_SECT_BOOTLD , QLA82XX_URI_BOOTLD_IDX_OFF ) ;
if ( uri_desc )
offset = cpu_to_le32 ( uri_desc - > findex ) ;
}
return ( u8 * ) & ha - > hablob - > fw - > data [ offset ] ;
}
static __le32
qla82xx_get_fw_size ( struct qla_hw_data * ha )
{
struct qla82xx_uri_data_desc * uri_desc = NULL ;
if ( ha - > fw_type = = QLA82XX_UNIFIED_ROMIMAGE ) {
uri_desc = qla82xx_get_data_desc ( ha , QLA82XX_URI_DIR_SECT_FW ,
QLA82XX_URI_FIRMWARE_IDX_OFF ) ;
if ( uri_desc )
return cpu_to_le32 ( uri_desc - > size ) ;
}
return cpu_to_le32 ( * ( u32 * ) & ha - > hablob - > fw - > data [ FW_SIZE_OFFSET ] ) ;
}
static u8 *
qla82xx_get_fw_offs ( struct qla_hw_data * ha )
{
u32 offset = IMAGE_START ;
struct qla82xx_uri_data_desc * uri_desc = NULL ;
if ( ha - > fw_type = = QLA82XX_UNIFIED_ROMIMAGE ) {
uri_desc = qla82xx_get_data_desc ( ha , QLA82XX_URI_DIR_SECT_FW ,
QLA82XX_URI_FIRMWARE_IDX_OFF ) ;
if ( uri_desc )
offset = cpu_to_le32 ( uri_desc - > findex ) ;
}
return ( u8 * ) & ha - > hablob - > fw - > data [ offset ] ;
}
2010-04-12 17:59:55 -07:00
/* PCI related functions */
char *
qla82xx_pci_info_str ( struct scsi_qla_host * vha , char * str )
{
int pcie_reg ;
struct qla_hw_data * ha = vha - > hw ;
char lwstr [ 6 ] ;
uint16_t lnk ;
pcie_reg = pci_find_capability ( ha - > pdev , PCI_CAP_ID_EXP ) ;
pci_read_config_word ( ha - > pdev , pcie_reg + PCI_EXP_LNKSTA , & lnk ) ;
ha - > link_width = ( lnk > > 4 ) & 0x3f ;
strcpy ( str , " PCIe ( " ) ;
strcat ( str , " 2.5Gb/s " ) ;
snprintf ( lwstr , sizeof ( lwstr ) , " x%d) " , ha - > link_width ) ;
strcat ( str , lwstr ) ;
return str ;
}
int qla82xx_pci_region_offset ( struct pci_dev * pdev , int region )
{
unsigned long val = 0 ;
u32 control ;
switch ( region ) {
case 0 :
val = 0 ;
break ;
case 1 :
pci_read_config_dword ( pdev , QLA82XX_PCI_REG_MSIX_TBL , & control ) ;
val = control + QLA82XX_MSIX_TBL_SPACE ;
break ;
}
return val ;
}
int
qla82xx_iospace_config ( struct qla_hw_data * ha )
{
uint32_t len = 0 ;
if ( pci_request_regions ( ha - > pdev , QLA2XXX_DRIVER_NAME ) ) {
2011-07-14 12:00:13 -07:00
ql_log_pci ( ql_log_fatal , ha - > pdev , 0x000c ,
" Failed to reserver selected regions. \n " ) ;
2010-04-12 17:59:55 -07:00
goto iospace_error_exit ;
}
/* Use MMIO operations for all accesses. */
if ( ! ( pci_resource_flags ( ha - > pdev , 0 ) & IORESOURCE_MEM ) ) {
2011-07-14 12:00:13 -07:00
ql_log_pci ( ql_log_fatal , ha - > pdev , 0x000d ,
" Region #0 not an MMIO resource, aborting. \n " ) ;
2010-04-12 17:59:55 -07:00
goto iospace_error_exit ;
}
len = pci_resource_len ( ha - > pdev , 0 ) ;
ha - > nx_pcibase =
( unsigned long ) ioremap ( pci_resource_start ( ha - > pdev , 0 ) , len ) ;
if ( ! ha - > nx_pcibase ) {
2011-07-14 12:00:13 -07:00
ql_log_pci ( ql_log_fatal , ha - > pdev , 0x000e ,
" Cannot remap pcibase MMIO, aborting. \n " ) ;
2010-04-12 17:59:55 -07:00
pci_release_regions ( ha - > pdev ) ;
goto iospace_error_exit ;
}
/* Mapping of IO base pointer */
ha - > iobase = ( device_reg_t __iomem * ) ( ( uint8_t * ) ha - > nx_pcibase +
0xbc000 + ( ha - > pdev - > devfn < < 11 ) ) ;
if ( ! ql2xdbwr ) {
ha - > nxdb_wr_ptr =
( unsigned long ) ioremap ( ( pci_resource_start ( ha - > pdev , 4 ) +
( ha - > pdev - > devfn < < 12 ) ) , 4 ) ;
if ( ! ha - > nxdb_wr_ptr ) {
2011-07-14 12:00:13 -07:00
ql_log_pci ( ql_log_fatal , ha - > pdev , 0x000f ,
" Cannot remap MMIO, aborting. \n " ) ;
2010-04-12 17:59:55 -07:00
pci_release_regions ( ha - > pdev ) ;
goto iospace_error_exit ;
}
/* Mapping of IO base pointer,
* door bell read and write pointer
*/
ha - > nxdb_rd_ptr = ( uint8_t * ) ha - > nx_pcibase + ( 512 * 1024 ) +
( ha - > pdev - > devfn * 8 ) ;
} else {
ha - > nxdb_wr_ptr = ( ha - > pdev - > devfn = = 6 ?
QLA82XX_CAMRAM_DB1 :
QLA82XX_CAMRAM_DB2 ) ;
}
ha - > max_req_queues = ha - > max_rsp_queues = 1 ;
ha - > msix_count = ha - > max_rsp_queues + 1 ;
2011-07-14 12:00:13 -07:00
ql_dbg_pci ( ql_dbg_multiq , ha - > pdev , 0xc006 ,
" nx_pci_base=%p iobase=%p "
" max_req_queues=%d msix_count=%d. \n " ,
2011-11-18 09:03:06 -08:00
( void * ) ha - > nx_pcibase , ha - > iobase ,
2011-07-14 12:00:13 -07:00
ha - > max_req_queues , ha - > msix_count ) ;
ql_dbg_pci ( ql_dbg_init , ha - > pdev , 0x0010 ,
" nx_pci_base=%p iobase=%p "
" max_req_queues=%d msix_count=%d. \n " ,
2011-11-18 09:03:06 -08:00
( void * ) ha - > nx_pcibase , ha - > iobase ,
2011-07-14 12:00:13 -07:00
ha - > max_req_queues , ha - > msix_count ) ;
2010-04-12 17:59:55 -07:00
return 0 ;
iospace_error_exit :
return - ENOMEM ;
}
/* GS related functions */
/* Initialization related functions */
/**
* qla82xx_pci_config ( ) - Setup ISP82xx PCI configuration registers .
* @ ha : HA context
*
* Returns 0 on success .
*/
int
qla82xx_pci_config ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
int ret ;
pci_set_master ( ha - > pdev ) ;
ret = pci_set_mwi ( ha - > pdev ) ;
ha - > chip_revision = ha - > pdev - > revision ;
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_init , vha , 0x0043 ,
2011-11-18 09:03:06 -08:00
" Chip revision:%d. \n " ,
2011-07-14 12:00:13 -07:00
ha - > chip_revision ) ;
2010-04-12 17:59:55 -07:00
return 0 ;
}
/**
* qla82xx_reset_chip ( ) - Setup ISP82xx PCI configuration registers .
* @ ha : HA context
*
* Returns 0 on success .
*/
void
qla82xx_reset_chip ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
ha - > isp_ops - > disable_intrs ( ha ) ;
}
void qla82xx_config_rings ( struct scsi_qla_host * vha )
{
struct qla_hw_data * ha = vha - > hw ;
struct device_reg_82xx __iomem * reg = & ha - > iobase - > isp82 ;
struct init_cb_81xx * icb ;
struct req_que * req = ha - > req_q_map [ 0 ] ;
struct rsp_que * rsp = ha - > rsp_q_map [ 0 ] ;
/* Setup ring parameters in initialization control block. */
icb = ( struct init_cb_81xx * ) ha - > init_cb ;
icb - > request_q_outpointer = __constant_cpu_to_le16 ( 0 ) ;
icb - > response_q_inpointer = __constant_cpu_to_le16 ( 0 ) ;
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 ) ) ;
WRT_REG_DWORD ( ( unsigned long __iomem * ) & reg - > req_q_out [ 0 ] , 0 ) ;
WRT_REG_DWORD ( ( unsigned long __iomem * ) & reg - > rsp_q_in [ 0 ] , 0 ) ;
WRT_REG_DWORD ( ( unsigned long __iomem * ) & reg - > rsp_q_out [ 0 ] , 0 ) ;
}
2010-05-04 15:01:34 -07:00
void qla82xx_reset_adapter ( struct scsi_qla_host * vha )
{
struct qla_hw_data * ha = vha - > hw ;
vha - > flags . online = 0 ;
qla2x00_try_to_stop_firmware ( vha ) ;
ha - > isp_ops - > disable_intrs ( ha ) ;
}
2010-09-03 15:20:52 -07:00
static int
qla82xx_fw_load_from_blob ( struct qla_hw_data * ha )
2010-04-12 17:59:55 -07:00
{
u64 * ptr64 ;
u32 i , flashaddr , size ;
__le64 data ;
size = ( IMAGE_START - BOOTLD_START ) / 8 ;
2010-05-28 15:08:23 -07:00
ptr64 = ( u64 * ) qla82xx_get_bootld_offset ( ha ) ;
2010-04-12 17:59:55 -07:00
flashaddr = BOOTLD_START ;
for ( i = 0 ; i < size ; i + + ) {
data = cpu_to_le64 ( ptr64 [ i ] ) ;
2010-05-28 15:08:23 -07:00
if ( qla82xx_pci_mem_write_2M ( ha , flashaddr , & data , 8 ) )
return - EIO ;
2010-04-12 17:59:55 -07:00
flashaddr + = 8 ;
}
flashaddr = FLASH_ADDR_START ;
2010-05-28 15:08:23 -07:00
size = ( __force u32 ) qla82xx_get_fw_size ( ha ) / 8 ;
ptr64 = ( u64 * ) qla82xx_get_fw_offs ( ha ) ;
2010-04-12 17:59:55 -07:00
for ( i = 0 ; i < size ; i + + ) {
data = cpu_to_le64 ( ptr64 [ i ] ) ;
if ( qla82xx_pci_mem_write_2M ( ha , flashaddr , & data , 8 ) )
return - EIO ;
flashaddr + = 8 ;
}
2010-05-28 15:08:23 -07:00
udelay ( 100 ) ;
2010-04-12 17:59:55 -07:00
/* Write a magic value to CAMRAM register
* at a specified offset to indicate
* that all data is written and
* ready for firmware to initialize .
*/
2010-05-28 15:08:23 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CAM_RAM ( 0x1fc ) , QLA82XX_BDINFO_MAGIC ) ;
2010-04-12 17:59:55 -07:00
2010-05-28 15:08:23 -07:00
read_lock ( & ha - > hw_lock ) ;
2010-07-23 15:28:34 +05:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_0 + 0x18 , 0x1020 ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET , 0x80001e ) ;
2010-05-28 15:08:23 -07:00
read_unlock ( & ha - > hw_lock ) ;
return 0 ;
}
static int
qla82xx_set_product_offset ( struct qla_hw_data * ha )
{
struct qla82xx_uri_table_desc * ptab_desc = NULL ;
const uint8_t * unirom = ha - > hablob - > fw - > data ;
uint32_t i ;
__le32 entries ;
__le32 flags , file_chiprev , offset ;
uint8_t chiprev = ha - > chip_revision ;
/* Hardcoding mn_present flag for P3P */
int mn_present = 0 ;
uint32_t flagbit ;
ptab_desc = qla82xx_get_table_desc ( unirom ,
QLA82XX_URI_DIR_SECT_PRODUCT_TBL ) ;
if ( ! ptab_desc )
return - 1 ;
entries = cpu_to_le32 ( ptab_desc - > num_entries ) ;
for ( i = 0 ; i < entries ; i + + ) {
offset = cpu_to_le32 ( ptab_desc - > findex ) +
( i * cpu_to_le32 ( ptab_desc - > entry_size ) ) ;
flags = cpu_to_le32 ( * ( ( int * ) & unirom [ offset ] +
QLA82XX_URI_FLAGS_OFF ) ) ;
file_chiprev = cpu_to_le32 ( * ( ( int * ) & unirom [ offset ] +
QLA82XX_URI_CHIP_REV_OFF ) ) ;
flagbit = mn_present ? 1 : 2 ;
if ( ( chiprev = = file_chiprev ) & & ( ( 1ULL < < flagbit ) & flags ) ) {
ha - > file_prd_off = offset ;
return 0 ;
}
}
return - 1 ;
}
int
qla82xx_validate_firmware_blob ( scsi_qla_host_t * vha , uint8_t fw_type )
{
__le32 val ;
uint32_t min_size ;
struct qla_hw_data * ha = vha - > hw ;
const struct firmware * fw = ha - > hablob - > fw ;
ha - > fw_type = fw_type ;
if ( fw_type = = QLA82XX_UNIFIED_ROMIMAGE ) {
if ( qla82xx_set_product_offset ( ha ) )
return - EINVAL ;
min_size = QLA82XX_URI_FW_MIN_SIZE ;
} else {
val = cpu_to_le32 ( * ( u32 * ) & fw - > data [ QLA82XX_FW_MAGIC_OFFSET ] ) ;
if ( ( __force u32 ) val ! = QLA82XX_BDINFO_MAGIC )
return - EINVAL ;
min_size = QLA82XX_FW_MIN_SIZE ;
}
if ( fw - > size < min_size )
return - EINVAL ;
2010-04-12 17:59:55 -07:00
return 0 ;
}
2010-09-03 15:20:52 -07:00
static int
qla82xx_check_cmdpeg_state ( struct qla_hw_data * ha )
2010-04-12 17:59:55 -07:00
{
u32 val = 0 ;
int retries = 60 ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
do {
read_lock ( & ha - > hw_lock ) ;
val = qla82xx_rd_32 ( ha , CRB_CMDPEG_STATE ) ;
read_unlock ( & ha - > hw_lock ) ;
switch ( val ) {
case PHAN_INITIALIZE_COMPLETE :
case PHAN_INITIALIZE_ACK :
return QLA_SUCCESS ;
case PHAN_INITIALIZE_FAILED :
break ;
default :
break ;
}
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x00a8 ,
" CRB_CMDPEG_STATE: 0x%x and retries:0x%x. \n " ,
val , retries ) ;
2010-04-12 17:59:55 -07:00
msleep ( 500 ) ;
} while ( - - retries ) ;
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00a9 ,
2010-04-12 17:59:55 -07:00
" Cmd Peg initialization failed: 0x%x. \n " , val ) ;
val = qla82xx_rd_32 ( ha , QLA82XX_ROMUSB_GLB_PEGTUNE_DONE ) ;
read_lock ( & ha - > hw_lock ) ;
qla82xx_wr_32 ( ha , CRB_CMDPEG_STATE , PHAN_INITIALIZE_FAILED ) ;
read_unlock ( & ha - > hw_lock ) ;
return QLA_FUNCTION_FAILED ;
}
2010-09-03 15:20:52 -07:00
static int
qla82xx_check_rcvpeg_state ( struct qla_hw_data * ha )
2010-04-12 17:59:55 -07:00
{
u32 val = 0 ;
int retries = 60 ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
do {
read_lock ( & ha - > hw_lock ) ;
val = qla82xx_rd_32 ( ha , CRB_RCVPEG_STATE ) ;
read_unlock ( & ha - > hw_lock ) ;
switch ( val ) {
case PHAN_INITIALIZE_COMPLETE :
case PHAN_INITIALIZE_ACK :
return QLA_SUCCESS ;
case PHAN_INITIALIZE_FAILED :
break ;
default :
break ;
}
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x00ab ,
" CRB_RCVPEG_STATE: 0x%x and retries: 0x%x. \n " ,
val , retries ) ;
2010-04-12 17:59:55 -07:00
msleep ( 500 ) ;
} while ( - - retries ) ;
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00ac ,
" Rcv Peg initializatin failed: 0x%x. \n " , val ) ;
2010-04-12 17:59:55 -07:00
read_lock ( & ha - > hw_lock ) ;
qla82xx_wr_32 ( ha , CRB_RCVPEG_STATE , PHAN_INITIALIZE_FAILED ) ;
read_unlock ( & ha - > hw_lock ) ;
return QLA_FUNCTION_FAILED ;
}
/* ISR related functions */
uint32_t qla82xx_isr_int_target_mask_enable [ 8 ] = {
ISR_INT_TARGET_MASK , ISR_INT_TARGET_MASK_F1 ,
ISR_INT_TARGET_MASK_F2 , ISR_INT_TARGET_MASK_F3 ,
ISR_INT_TARGET_MASK_F4 , ISR_INT_TARGET_MASK_F5 ,
ISR_INT_TARGET_MASK_F7 , ISR_INT_TARGET_MASK_F7
} ;
uint32_t qla82xx_isr_int_target_status [ 8 ] = {
ISR_INT_TARGET_STATUS , ISR_INT_TARGET_STATUS_F1 ,
ISR_INT_TARGET_STATUS_F2 , ISR_INT_TARGET_STATUS_F3 ,
ISR_INT_TARGET_STATUS_F4 , ISR_INT_TARGET_STATUS_F5 ,
ISR_INT_TARGET_STATUS_F7 , ISR_INT_TARGET_STATUS_F7
} ;
static struct qla82xx_legacy_intr_set legacy_intr [ ] = \
QLA82XX_LEGACY_INTR_CONFIG ;
/*
* qla82xx_mbx_completion ( ) - Process mailbox command completions .
* @ ha : SCSI driver HA context
* @ mb0 : Mailbox0 register
*/
2010-09-03 15:20:52 -07:00
static void
2010-04-12 17:59:55 -07:00
qla82xx_mbx_completion ( scsi_qla_host_t * vha , uint16_t mb0 )
{
uint16_t cnt ;
uint16_t __iomem * wptr ;
struct qla_hw_data * ha = vha - > hw ;
struct device_reg_82xx __iomem * reg = & ha - > iobase - > isp82 ;
wptr = ( uint16_t __iomem * ) & reg - > mailbox_out [ 1 ] ;
/* Load return mailbox registers. */
ha - > flags . mbox_int = 1 ;
ha - > mailbox_out [ 0 ] = mb0 ;
for ( cnt = 1 ; cnt < ha - > mbx_count ; cnt + + ) {
ha - > mailbox_out [ cnt ] = RD_REG_WORD ( wptr ) ;
wptr + + ;
}
2011-11-18 09:03:07 -08:00
if ( ! ha - > mcp )
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_async , vha , 0x5053 ,
" MBX pointer ERROR. \n " ) ;
2010-04-12 17:59:55 -07:00
}
/*
* qla82xx_intr_handler ( ) - Process interrupts for the ISP23xx and ISP63xx .
* @ irq :
* @ dev_id : SCSI driver HA context
* @ regs :
*
* Called by system whenever the host adapter generates an interrupt .
*
* Returns handled flag .
*/
irqreturn_t
qla82xx_intr_handler ( int irq , void * dev_id )
{
scsi_qla_host_t * vha ;
struct qla_hw_data * ha ;
struct rsp_que * rsp ;
struct device_reg_82xx __iomem * reg ;
int status = 0 , status1 = 0 ;
unsigned long flags ;
unsigned long iter ;
2011-07-14 12:00:13 -07:00
uint32_t stat = 0 ;
2010-04-12 17:59:55 -07:00
uint16_t mb [ 4 ] ;
rsp = ( struct rsp_que * ) dev_id ;
if ( ! rsp ) {
2012-02-09 11:15:47 -08:00
ql_log ( ql_log_info , NULL , 0xb054 ,
" %s: NULL response queue pointer. \n " , __func__ ) ;
2010-04-12 17:59:55 -07:00
return IRQ_NONE ;
}
ha = rsp - > hw ;
if ( ! ha - > flags . msi_enabled ) {
status = qla82xx_rd_32 ( ha , ISR_INT_VECTOR ) ;
if ( ! ( status & ha - > nx_legacy_intr . int_vec_bit ) )
return IRQ_NONE ;
status1 = qla82xx_rd_32 ( ha , ISR_INT_STATE_REG ) ;
if ( ! ISR_IS_LEGACY_INTR_TRIGGERED ( status1 ) )
return IRQ_NONE ;
}
/* clear the interrupt */
qla82xx_wr_32 ( ha , ha - > nx_legacy_intr . tgt_status_reg , 0xffffffff ) ;
/* read twice to ensure write is flushed */
qla82xx_rd_32 ( ha , ISR_INT_VECTOR ) ;
qla82xx_rd_32 ( ha , ISR_INT_VECTOR ) ;
reg = & ha - > iobase - > isp82 ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
vha = pci_get_drvdata ( ha - > pdev ) ;
for ( iter = 1 ; iter - - ; ) {
if ( RD_REG_DWORD ( & reg - > host_int ) ) {
stat = RD_REG_DWORD ( & reg - > host_status ) ;
switch ( stat & 0xff ) {
case 0x1 :
case 0x2 :
case 0x10 :
case 0x11 :
qla82xx_mbx_completion ( vha , MSW ( stat ) ) ;
status | = MBX_INTERRUPT ;
break ;
case 0x12 :
mb [ 0 ] = MSW ( stat ) ;
mb [ 1 ] = RD_REG_WORD ( & reg - > mailbox_out [ 1 ] ) ;
mb [ 2 ] = RD_REG_WORD ( & reg - > mailbox_out [ 2 ] ) ;
mb [ 3 ] = RD_REG_WORD ( & reg - > mailbox_out [ 3 ] ) ;
qla2x00_async_event ( vha , rsp , mb ) ;
break ;
case 0x13 :
qla24xx_process_response_queue ( vha , rsp ) ;
break ;
default :
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_async , vha , 0x5054 ,
" Unrecognized interrupt type (%d). \n " ,
stat & 0xff ) ;
2010-04-12 17:59:55 -07:00
break ;
}
}
WRT_REG_DWORD ( & reg - > host_int , 0 ) ;
}
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
if ( ! ha - > flags . msi_enabled )
qla82xx_wr_32 ( ha , ha - > nx_legacy_intr . tgt_mask_reg , 0xfbff ) ;
# ifdef QL_DEBUG_LEVEL_17
if ( ! irq & & ha - > flags . eeh_busy )
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x503d ,
" isr:status %x, cmd_flags %lx, mbox_int %x, stat %x. \n " ,
2010-04-12 17:59:55 -07:00
status , ha - > mbx_cmd_flags , ha - > flags . mbox_int , stat ) ;
# endif
if ( test_bit ( MBX_INTR_WAIT , & ha - > mbx_cmd_flags ) & &
( status & MBX_INTERRUPT ) & & ha - > flags . mbox_int ) {
set_bit ( MBX_INTERRUPT , & ha - > mbx_cmd_flags ) ;
complete ( & ha - > mbx_intr_comp ) ;
}
return IRQ_HANDLED ;
}
irqreturn_t
qla82xx_msix_default ( int irq , void * dev_id )
{
scsi_qla_host_t * vha ;
struct qla_hw_data * ha ;
struct rsp_que * rsp ;
struct device_reg_82xx __iomem * reg ;
int status = 0 ;
unsigned long flags ;
2011-07-14 12:00:13 -07:00
uint32_t stat = 0 ;
2010-04-12 17:59:55 -07:00
uint16_t mb [ 4 ] ;
rsp = ( struct rsp_que * ) dev_id ;
if ( ! rsp ) {
printk ( KERN_INFO
2011-07-14 12:00:13 -07:00
" %s(): NULL response queue pointer. \n " , __func__ ) ;
2010-04-12 17:59:55 -07:00
return IRQ_NONE ;
}
ha = rsp - > hw ;
reg = & ha - > iobase - > isp82 ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
vha = pci_get_drvdata ( ha - > pdev ) ;
do {
if ( RD_REG_DWORD ( & reg - > host_int ) ) {
stat = RD_REG_DWORD ( & reg - > host_status ) ;
switch ( stat & 0xff ) {
case 0x1 :
case 0x2 :
case 0x10 :
case 0x11 :
qla82xx_mbx_completion ( vha , MSW ( stat ) ) ;
status | = MBX_INTERRUPT ;
break ;
case 0x12 :
mb [ 0 ] = MSW ( stat ) ;
mb [ 1 ] = RD_REG_WORD ( & reg - > mailbox_out [ 1 ] ) ;
mb [ 2 ] = RD_REG_WORD ( & reg - > mailbox_out [ 2 ] ) ;
mb [ 3 ] = RD_REG_WORD ( & reg - > mailbox_out [ 3 ] ) ;
qla2x00_async_event ( vha , rsp , mb ) ;
break ;
case 0x13 :
qla24xx_process_response_queue ( vha , rsp ) ;
break ;
default :
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_async , vha , 0x5041 ,
" Unrecognized interrupt type (%d). \n " ,
stat & 0xff ) ;
2010-04-12 17:59:55 -07:00
break ;
}
}
WRT_REG_DWORD ( & reg - > host_int , 0 ) ;
} while ( 0 ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
# ifdef QL_DEBUG_LEVEL_17
if ( ! irq & & ha - > flags . eeh_busy )
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x5044 ,
" isr:status %x, cmd_flags %lx, mbox_int %x, stat %x. \n " ,
status , ha - > mbx_cmd_flags , ha - > flags . mbox_int , stat ) ;
2010-04-12 17:59:55 -07:00
# endif
if ( test_bit ( MBX_INTR_WAIT , & ha - > mbx_cmd_flags ) & &
( status & MBX_INTERRUPT ) & & ha - > flags . mbox_int ) {
set_bit ( MBX_INTERRUPT , & ha - > mbx_cmd_flags ) ;
complete ( & ha - > mbx_intr_comp ) ;
}
return IRQ_HANDLED ;
}
irqreturn_t
qla82xx_msix_rsp_q ( int irq , void * dev_id )
{
scsi_qla_host_t * vha ;
struct qla_hw_data * ha ;
struct rsp_que * rsp ;
struct device_reg_82xx __iomem * reg ;
2011-08-16 11:29:27 -07:00
unsigned long flags ;
2010-04-12 17:59:55 -07:00
rsp = ( struct rsp_que * ) dev_id ;
if ( ! rsp ) {
printk ( KERN_INFO
2011-07-14 12:00:13 -07:00
" %s(): NULL response queue pointer. \n " , __func__ ) ;
2010-04-12 17:59:55 -07:00
return IRQ_NONE ;
}
ha = rsp - > hw ;
reg = & ha - > iobase - > isp82 ;
2011-08-16 11:29:27 -07:00
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
2010-04-12 17:59:55 -07:00
vha = pci_get_drvdata ( ha - > pdev ) ;
qla24xx_process_response_queue ( vha , rsp ) ;
WRT_REG_DWORD ( & reg - > host_int , 0 ) ;
2011-08-16 11:29:27 -07:00
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
2010-04-12 17:59:55 -07:00
return IRQ_HANDLED ;
}
void
qla82xx_poll ( int irq , void * dev_id )
{
scsi_qla_host_t * vha ;
struct qla_hw_data * ha ;
struct rsp_que * rsp ;
struct device_reg_82xx __iomem * reg ;
int status = 0 ;
uint32_t stat ;
uint16_t mb [ 4 ] ;
unsigned long flags ;
rsp = ( struct rsp_que * ) dev_id ;
if ( ! rsp ) {
printk ( KERN_INFO
2011-07-14 12:00:13 -07:00
" %s(): NULL response queue pointer. \n " , __func__ ) ;
2010-04-12 17:59:55 -07:00
return ;
}
ha = rsp - > hw ;
reg = & ha - > iobase - > isp82 ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
vha = pci_get_drvdata ( ha - > pdev ) ;
if ( RD_REG_DWORD ( & reg - > host_int ) ) {
stat = RD_REG_DWORD ( & reg - > host_status ) ;
switch ( stat & 0xff ) {
case 0x1 :
case 0x2 :
case 0x10 :
case 0x11 :
qla82xx_mbx_completion ( vha , MSW ( stat ) ) ;
status | = MBX_INTERRUPT ;
break ;
case 0x12 :
mb [ 0 ] = MSW ( stat ) ;
mb [ 1 ] = RD_REG_WORD ( & reg - > mailbox_out [ 1 ] ) ;
mb [ 2 ] = RD_REG_WORD ( & reg - > mailbox_out [ 2 ] ) ;
mb [ 3 ] = RD_REG_WORD ( & reg - > mailbox_out [ 3 ] ) ;
qla2x00_async_event ( vha , rsp , mb ) ;
break ;
case 0x13 :
qla24xx_process_response_queue ( vha , rsp ) ;
break ;
default :
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb013 ,
" Unrecognized interrupt type (%d). \n " ,
stat * 0xff ) ;
2010-04-12 17:59:55 -07:00
break ;
}
}
WRT_REG_DWORD ( & reg - > host_int , 0 ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
}
void
qla82xx_enable_intrs ( struct qla_hw_data * ha )
{
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
qla82xx_mbx_intr_enable ( vha ) ;
spin_lock_irq ( & ha - > hardware_lock ) ;
qla82xx_wr_32 ( ha , ha - > nx_legacy_intr . tgt_mask_reg , 0xfbff ) ;
spin_unlock_irq ( & ha - > hardware_lock ) ;
ha - > interrupts_on = 1 ;
}
void
qla82xx_disable_intrs ( struct qla_hw_data * ha )
{
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
qla82xx_mbx_intr_disable ( vha ) ;
spin_lock_irq ( & ha - > hardware_lock ) ;
qla82xx_wr_32 ( ha , ha - > nx_legacy_intr . tgt_mask_reg , 0x0400 ) ;
spin_unlock_irq ( & ha - > hardware_lock ) ;
ha - > interrupts_on = 0 ;
}
void qla82xx_init_flags ( struct qla_hw_data * ha )
{
struct qla82xx_legacy_intr_set * nx_legacy_intr ;
/* ISP 8021 initializations */
rwlock_init ( & ha - > hw_lock ) ;
ha - > qdr_sn_window = - 1 ;
ha - > ddr_mn_window = - 1 ;
ha - > curr_window = 255 ;
ha - > portnum = PCI_FUNC ( ha - > pdev - > devfn ) ;
nx_legacy_intr = & legacy_intr [ ha - > portnum ] ;
ha - > nx_legacy_intr . int_vec_bit = nx_legacy_intr - > int_vec_bit ;
ha - > nx_legacy_intr . tgt_status_reg = nx_legacy_intr - > tgt_status_reg ;
ha - > nx_legacy_intr . tgt_mask_reg = nx_legacy_intr - > tgt_mask_reg ;
ha - > nx_legacy_intr . pci_int_reg = nx_legacy_intr - > pci_int_reg ;
}
2010-09-03 15:20:50 -07:00
inline void
2010-04-12 17:59:55 -07:00
qla82xx_set_drv_active ( scsi_qla_host_t * vha )
{
uint32_t drv_active ;
struct qla_hw_data * ha = vha - > hw ;
drv_active = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
/* If reset value is all FF's, initialize DRV_ACTIVE */
if ( drv_active = = 0xffffffff ) {
2010-09-03 15:20:52 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ,
QLA82XX_DRV_NOT_ACTIVE ) ;
2010-04-12 17:59:55 -07:00
drv_active = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
}
2010-09-03 15:20:52 -07:00
drv_active | = ( QLA82XX_DRV_ACTIVE < < ( ha - > portnum * 4 ) ) ;
2010-04-12 17:59:55 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DRV_ACTIVE , drv_active ) ;
}
inline void
qla82xx_clear_drv_active ( struct qla_hw_data * ha )
{
uint32_t drv_active ;
drv_active = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
2010-09-03 15:20:52 -07:00
drv_active & = ~ ( QLA82XX_DRV_ACTIVE < < ( ha - > portnum * 4 ) ) ;
2010-04-12 17:59:55 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DRV_ACTIVE , drv_active ) ;
}
static inline int
qla82xx_need_reset ( struct qla_hw_data * ha )
{
uint32_t drv_state ;
int rval ;
2011-08-16 11:31:44 -07:00
if ( ha - > flags . isp82xx_reset_owner )
return 1 ;
else {
drv_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
rval = drv_state & ( QLA82XX_DRVST_RST_RDY < < ( ha - > portnum * 4 ) ) ;
return rval ;
}
2010-04-12 17:59:55 -07:00
}
static inline void
qla82xx_set_rst_ready ( struct qla_hw_data * ha )
{
uint32_t drv_state ;
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
drv_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
/* If reset value is all FF's, initialize DRV_STATE */
if ( drv_state = = 0xffffffff ) {
2010-09-03 15:20:52 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DRV_STATE , QLA82XX_DRVST_NOT_RDY ) ;
2010-04-12 17:59:55 -07:00
drv_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
}
drv_state | = ( QLA82XX_DRVST_RST_RDY < < ( ha - > portnum * 4 ) ) ;
2011-08-16 11:31:44 -07:00
ql_dbg ( ql_dbg_init , vha , 0x00bb ,
" drv_state = 0x%08x. \n " , drv_state ) ;
2010-04-12 17:59:55 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DRV_STATE , drv_state ) ;
}
static inline void
qla82xx_clear_rst_ready ( struct qla_hw_data * ha )
{
uint32_t drv_state ;
drv_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
drv_state & = ~ ( QLA82XX_DRVST_RST_RDY < < ( ha - > portnum * 4 ) ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_DRV_STATE , drv_state ) ;
}
static inline void
qla82xx_set_qsnt_ready ( struct qla_hw_data * ha )
{
uint32_t qsnt_state ;
qsnt_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
qsnt_state | = ( QLA82XX_DRVST_QSNT_RDY < < ( ha - > portnum * 4 ) ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_DRV_STATE , qsnt_state ) ;
}
2010-12-21 16:00:14 -08:00
void
qla82xx_clear_qsnt_ready ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t qsnt_state ;
qsnt_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
qsnt_state & = ~ ( QLA82XX_DRVST_QSNT_RDY < < ( ha - > portnum * 4 ) ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_DRV_STATE , qsnt_state ) ;
}
2010-09-03 15:20:52 -07:00
static int
qla82xx_load_fw ( scsi_qla_host_t * vha )
2010-04-12 17:59:55 -07:00
{
int rst ;
struct fw_blob * blob ;
struct qla_hw_data * ha = vha - > hw ;
if ( qla82xx_pinit_from_rom ( vha ) ! = QLA_SUCCESS ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x009f ,
" Error during CRB initialization. \n " ) ;
2010-04-12 17:59:55 -07:00
return QLA_FUNCTION_FAILED ;
}
udelay ( 500 ) ;
/* Bring QM and CAMRAM out of reset */
rst = qla82xx_rd_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET ) ;
rst & = ~ ( ( 1 < < 28 ) | ( 1 < < 24 ) ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET , rst ) ;
/*
* FW Load priority :
* 1 ) Operational firmware residing in flash .
* 2 ) Firmware via request - firmware interface ( . bin file ) .
*/
if ( ql2xfwloadbin = = 2 )
goto try_blob_fw ;
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x00a0 ,
" Attempting to load firmware from flash. \n " ) ;
2010-04-12 17:59:55 -07:00
if ( qla82xx_fw_load_from_flash ( ha ) = = QLA_SUCCESS ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x00a1 ,
" Firmware loaded successully from flash. \n " ) ;
2010-04-12 17:59:55 -07:00
return QLA_SUCCESS ;
2011-05-10 11:30:09 -07:00
} else {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x0108 ,
" Firmware load from flash failed. \n " ) ;
2010-04-12 17:59:55 -07:00
}
2011-05-10 11:30:09 -07:00
2010-04-12 17:59:55 -07:00
try_blob_fw :
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x00a2 ,
" Attempting to load firmware from blob. \n " ) ;
2010-04-12 17:59:55 -07:00
/* Load firmware blob. */
blob = ha - > hablob = qla2x00_request_firmware ( vha ) ;
if ( ! blob ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00a3 ,
" Firmware image not preset. \n " ) ;
2010-04-12 17:59:55 -07:00
goto fw_load_failed ;
}
2010-05-28 15:08:23 -07:00
/* Validating firmware blob */
if ( qla82xx_validate_firmware_blob ( vha ,
QLA82XX_FLASH_ROMIMAGE ) ) {
/* Fallback to URI format */
if ( qla82xx_validate_firmware_blob ( vha ,
QLA82XX_UNIFIED_ROMIMAGE ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00a4 ,
" No valid firmware image found. \n " ) ;
2010-05-28 15:08:23 -07:00
return QLA_FUNCTION_FAILED ;
}
}
2010-04-12 17:59:55 -07:00
if ( qla82xx_fw_load_from_blob ( ha ) = = QLA_SUCCESS ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x00a5 ,
" Firmware loaded successfully from binary blob. \n " ) ;
2010-04-12 17:59:55 -07:00
return QLA_SUCCESS ;
} else {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00a6 ,
" Firmware load failed for binary blob. \n " ) ;
2010-04-12 17:59:55 -07:00
blob - > fw = NULL ;
blob = NULL ;
goto fw_load_failed ;
}
return QLA_SUCCESS ;
fw_load_failed :
return QLA_FUNCTION_FAILED ;
}
2010-09-03 15:20:50 -07:00
int
2010-04-12 17:59:55 -07:00
qla82xx_start_firmware ( scsi_qla_host_t * vha )
{
int pcie_cap ;
uint16_t lnk ;
struct qla_hw_data * ha = vha - > hw ;
/* scrub dma mask expansion register */
2010-09-03 15:20:52 -07:00
qla82xx_wr_32 ( ha , CRB_DMA_SHIFT , QLA82XX_DMA_SHIFT_VALUE ) ;
2010-04-12 17:59:55 -07:00
2010-07-23 15:28:34 +05:00
/* Put both the PEG CMD and RCV PEG to default state
* of 0 before resetting the hardware
*/
qla82xx_wr_32 ( ha , CRB_CMDPEG_STATE , 0 ) ;
qla82xx_wr_32 ( ha , CRB_RCVPEG_STATE , 0 ) ;
2010-04-12 17:59:55 -07:00
/* Overwrite stale initialization register values */
qla82xx_wr_32 ( ha , QLA82XX_PEG_HALT_STATUS1 , 0 ) ;
qla82xx_wr_32 ( ha , QLA82XX_PEG_HALT_STATUS2 , 0 ) ;
if ( qla82xx_load_fw ( vha ) ! = QLA_SUCCESS ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00a7 ,
" Error trying to start fw. \n " ) ;
2010-04-12 17:59:55 -07:00
return QLA_FUNCTION_FAILED ;
}
/* Handshake with the card before we register the devices. */
if ( qla82xx_check_cmdpeg_state ( ha ) ! = QLA_SUCCESS ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00aa ,
" Error during card handshake. \n " ) ;
2010-04-12 17:59:55 -07:00
return QLA_FUNCTION_FAILED ;
}
/* Negotiated Link width */
pcie_cap = pci_find_capability ( ha - > pdev , PCI_CAP_ID_EXP ) ;
pci_read_config_word ( ha - > pdev , pcie_cap + PCI_EXP_LNKSTA , & lnk ) ;
ha - > link_width = ( lnk > > 4 ) & 0x3f ;
/* Synchronize with Receive peg */
return qla82xx_check_rcvpeg_state ( ha ) ;
}
2010-09-03 15:20:52 -07:00
static uint32_t *
2010-04-12 17:59:55 -07:00
qla82xx_read_flash_data ( scsi_qla_host_t * vha , uint32_t * dwptr , uint32_t faddr ,
uint32_t length )
{
uint32_t i ;
uint32_t val ;
struct qla_hw_data * ha = vha - > hw ;
/* Dword reads to flash. */
for ( i = 0 ; i < length / 4 ; i + + , faddr + = 4 ) {
if ( qla82xx_rom_fast_read ( ha , faddr , & val ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x0106 ,
" Do ROM fast read failed. \n " ) ;
2010-04-12 17:59:55 -07:00
goto done_read ;
}
dwptr [ i ] = __constant_cpu_to_le32 ( val ) ;
}
done_read :
return dwptr ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_unprotect_flash ( struct qla_hw_data * ha )
{
int ret ;
uint32_t val ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
ret = ql82xx_rom_lock_d ( ha ) ;
if ( ret < 0 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb014 ,
" ROM Lock failed. \n " ) ;
2010-04-12 17:59:55 -07:00
return ret ;
}
ret = qla82xx_read_status_reg ( ha , & val ) ;
if ( ret < 0 )
goto done_unprotect ;
2010-05-28 15:08:26 -07:00
val & = ~ ( BLOCK_PROTECT_BITS < < 2 ) ;
2010-04-12 17:59:55 -07:00
ret = qla82xx_write_status_reg ( ha , val ) ;
if ( ret < 0 ) {
2010-05-28 15:08:26 -07:00
val | = ( BLOCK_PROTECT_BITS < < 2 ) ;
2010-04-12 17:59:55 -07:00
qla82xx_write_status_reg ( ha , val ) ;
}
if ( qla82xx_write_disable_flash ( ha ) ! = 0 )
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb015 ,
" Write disable failed. \n " ) ;
2010-04-12 17:59:55 -07:00
done_unprotect :
2011-05-10 11:30:10 -07:00
qla82xx_rom_unlock ( ha ) ;
2010-04-12 17:59:55 -07:00
return ret ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_protect_flash ( struct qla_hw_data * ha )
{
int ret ;
uint32_t val ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
ret = ql82xx_rom_lock_d ( ha ) ;
if ( ret < 0 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb016 ,
" ROM Lock failed. \n " ) ;
2010-04-12 17:59:55 -07:00
return ret ;
}
ret = qla82xx_read_status_reg ( ha , & val ) ;
if ( ret < 0 )
goto done_protect ;
2010-05-28 15:08:26 -07:00
val | = ( BLOCK_PROTECT_BITS < < 2 ) ;
2010-04-12 17:59:55 -07:00
/* LOCK all sectors */
ret = qla82xx_write_status_reg ( ha , val ) ;
if ( ret < 0 )
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb017 ,
" Write status register failed. \n " ) ;
2010-04-12 17:59:55 -07:00
if ( qla82xx_write_disable_flash ( ha ) ! = 0 )
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb018 ,
" Write disable failed. \n " ) ;
2010-04-12 17:59:55 -07:00
done_protect :
2011-05-10 11:30:10 -07:00
qla82xx_rom_unlock ( ha ) ;
2010-04-12 17:59:55 -07:00
return ret ;
}
2010-09-03 15:20:52 -07:00
static int
2010-04-12 17:59:55 -07:00
qla82xx_erase_sector ( struct qla_hw_data * ha , int addr )
{
int ret = 0 ;
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-04-12 17:59:55 -07:00
ret = ql82xx_rom_lock_d ( ha ) ;
if ( ret < 0 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb019 ,
" ROM Lock failed. \n " ) ;
2010-04-12 17:59:55 -07:00
return ret ;
}
qla82xx_flash_set_write_enable ( ha ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_ADDRESS , addr ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_ABYTE_CNT , 3 ) ;
qla82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_INSTR_OPCODE , M25P_INSTR_SE ) ;
if ( qla82xx_wait_rom_done ( ha ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb01a ,
" Error waiting for rom done. \n " ) ;
2010-04-12 17:59:55 -07:00
ret = - 1 ;
goto done ;
}
ret = qla82xx_flash_wait_write_finish ( ha ) ;
done :
2011-05-10 11:30:10 -07:00
qla82xx_rom_unlock ( ha ) ;
2010-04-12 17:59:55 -07:00
return ret ;
}
/*
* Address and length are byte address
*/
uint8_t *
qla82xx_read_optrom_data ( struct scsi_qla_host * vha , uint8_t * buf ,
uint32_t offset , uint32_t length )
{
scsi_block_requests ( vha - > host ) ;
qla82xx_read_flash_data ( vha , ( uint32_t * ) buf , offset , length ) ;
scsi_unblock_requests ( vha - > host ) ;
return buf ;
}
static int
qla82xx_write_flash_data ( struct scsi_qla_host * vha , uint32_t * dwptr ,
uint32_t faddr , uint32_t dwords )
{
int ret ;
uint32_t liter ;
uint32_t sec_mask , rest_addr ;
dma_addr_t optrom_dma ;
void * optrom = NULL ;
int page_mode = 0 ;
struct qla_hw_data * ha = vha - > hw ;
ret = - 1 ;
/* Prepare burst-capable write on supported ISPs. */
if ( page_mode & & ! ( faddr & 0xfff ) & &
dwords > OPTROM_BURST_DWORDS ) {
optrom = dma_alloc_coherent ( & ha - > pdev - > dev , OPTROM_BURST_SIZE ,
& optrom_dma , GFP_KERNEL ) ;
if ( ! optrom ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb01b ,
" Unable to allocate memory "
" for optron burst write (%x KB). \n " ,
OPTROM_BURST_SIZE / 1024 ) ;
2010-04-12 17:59:55 -07:00
}
}
rest_addr = ha - > fdt_block_size - 1 ;
sec_mask = ~ rest_addr ;
ret = qla82xx_unprotect_flash ( ha ) ;
if ( ret ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb01c ,
" Unable to unprotect flash for update. \n " ) ;
2010-04-12 17:59:55 -07:00
goto write_done ;
}
for ( liter = 0 ; liter < dwords ; liter + + , faddr + = 4 , dwptr + + ) {
/* Are we at the beginning of a sector? */
if ( ( faddr & rest_addr ) = = 0 ) {
ret = qla82xx_erase_sector ( ha , faddr ) ;
if ( ret ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb01d ,
" Unable to erase sector: address=%x. \n " ,
faddr ) ;
2010-04-12 17:59:55 -07:00
break ;
}
}
/* Go with burst-write. */
if ( optrom & & ( liter + OPTROM_BURST_DWORDS ) < = dwords ) {
/* Copy data to DMA'ble buffer. */
memcpy ( optrom , dwptr , OPTROM_BURST_SIZE ) ;
ret = qla2x00_load_ram ( vha , optrom_dma ,
( ha - > flash_data_off | faddr ) ,
OPTROM_BURST_DWORDS ) ;
if ( ret ! = QLA_SUCCESS ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb01e ,
2010-04-12 17:59:55 -07:00
" Unable to burst-write optrom segment "
" (%x/%x/%llx). \n " , ret ,
( ha - > flash_data_off | faddr ) ,
( unsigned long long ) optrom_dma ) ;
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb01f ,
2010-04-12 17:59:55 -07:00
" Reverting to slow-write. \n " ) ;
dma_free_coherent ( & ha - > pdev - > dev ,
OPTROM_BURST_SIZE , optrom , optrom_dma ) ;
optrom = NULL ;
} else {
liter + = OPTROM_BURST_DWORDS - 1 ;
faddr + = OPTROM_BURST_DWORDS - 1 ;
dwptr + = OPTROM_BURST_DWORDS - 1 ;
continue ;
}
}
ret = qla82xx_write_flash_dword ( ha , faddr ,
cpu_to_le32 ( * dwptr ) ) ;
if ( ret ) {
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb020 ,
" Unable to program flash address=%x data=%x. \n " ,
faddr , * dwptr ) ;
2010-04-12 17:59:55 -07:00
break ;
}
}
ret = qla82xx_protect_flash ( ha ) ;
if ( ret )
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0xb021 ,
2010-04-12 17:59:55 -07:00
" Unable to protect flash after update. \n " ) ;
write_done :
if ( optrom )
dma_free_coherent ( & ha - > pdev - > dev ,
OPTROM_BURST_SIZE , optrom , optrom_dma ) ;
return ret ;
}
int
qla82xx_write_optrom_data ( struct scsi_qla_host * vha , uint8_t * buf ,
uint32_t offset , uint32_t length )
{
int rval ;
/* Suspend HBA. */
scsi_block_requests ( vha - > host ) ;
rval = qla82xx_write_flash_data ( vha , ( uint32_t * ) buf , offset ,
length > > 2 ) ;
scsi_unblock_requests ( vha - > host ) ;
/* Convert return ISP82xx to generic */
if ( rval )
rval = QLA_FUNCTION_FAILED ;
else
rval = QLA_SUCCESS ;
return rval ;
}
void
2011-11-18 09:03:18 -08:00
qla82xx_start_iocbs ( scsi_qla_host_t * vha )
2010-04-12 17:59:55 -07:00
{
2011-11-18 09:03:18 -08:00
struct qla_hw_data * ha = vha - > hw ;
2010-04-12 17:59:55 -07:00
struct req_que * req = ha - > req_q_map [ 0 ] ;
struct device_reg_82xx __iomem * reg ;
uint32_t dbval ;
/* Adjust ring index. */
req - > ring_index + + ;
if ( req - > ring_index = = req - > length ) {
req - > ring_index = 0 ;
req - > ring_ptr = req - > ring ;
} else
req - > ring_ptr + + ;
reg = & ha - > iobase - > isp82 ;
dbval = 0x04 | ( ha - > portnum < < 5 ) ;
dbval = dbval | ( req - > id < < 8 ) | ( req - > ring_index < < 16 ) ;
2010-05-28 15:08:28 -07:00
if ( ql2xdbwr )
qla82xx_wr_32 ( ha , ha - > nxdb_wr_ptr , dbval ) ;
else {
WRT_REG_DWORD ( ( unsigned long __iomem * ) ha - > nxdb_wr_ptr , dbval ) ;
2010-04-12 17:59:55 -07:00
wmb ( ) ;
2010-05-28 15:08:28 -07:00
while ( RD_REG_DWORD ( ha - > nxdb_rd_ptr ) ! = dbval ) {
WRT_REG_DWORD ( ( unsigned long __iomem * ) ha - > nxdb_wr_ptr ,
dbval ) ;
wmb ( ) ;
}
2010-04-12 17:59:55 -07:00
}
}
2010-09-07 20:55:32 -07:00
void qla82xx_rom_lock_recovery ( struct qla_hw_data * ha )
{
2011-07-14 12:00:13 -07:00
scsi_qla_host_t * vha = pci_get_drvdata ( ha - > pdev ) ;
2010-09-07 20:55:32 -07:00
if ( qla82xx_rom_lock ( ha ) )
/* Someone else is holding the lock. */
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0xb022 ,
" Resetting rom_lock. \n " ) ;
2010-09-07 20:55:32 -07:00
/*
* Either we got the lock , or someone
* else died while holding it .
* In either case , unlock .
*/
2011-05-10 11:30:10 -07:00
qla82xx_rom_unlock ( ha ) ;
2010-09-07 20:55:32 -07:00
}
2010-04-12 17:59:55 -07:00
/*
* qla82xx_device_bootstrap
* Initialize device , set DEV_READY , start fw
*
* Note :
* IDC lock must be held upon entry
*
* Return :
* Success : 0
* Failed : 1
*/
static int
qla82xx_device_bootstrap ( scsi_qla_host_t * vha )
{
2010-09-07 20:55:32 -07:00
int rval = QLA_SUCCESS ;
int i , timeout ;
2010-04-12 17:59:55 -07:00
uint32_t old_count , count ;
struct qla_hw_data * ha = vha - > hw ;
2010-09-07 20:55:32 -07:00
int need_reset = 0 , peg_stuck = 1 ;
2010-04-12 17:59:55 -07:00
2010-09-07 20:55:32 -07:00
need_reset = qla82xx_need_reset ( ha ) ;
2010-04-12 17:59:55 -07:00
old_count = qla82xx_rd_32 ( ha , QLA82XX_PEG_ALIVE_COUNTER ) ;
for ( i = 0 ; i < 10 ; i + + ) {
timeout = msleep_interruptible ( 200 ) ;
if ( timeout ) {
qla82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE ,
QLA82XX_DEV_FAILED ) ;
return QLA_FUNCTION_FAILED ;
}
count = qla82xx_rd_32 ( ha , QLA82XX_PEG_ALIVE_COUNTER ) ;
if ( count ! = old_count )
2010-09-07 20:55:32 -07:00
peg_stuck = 0 ;
}
if ( need_reset ) {
/* We are trying to perform a recovery here. */
if ( peg_stuck )
qla82xx_rom_lock_recovery ( ha ) ;
goto dev_initialize ;
} else {
/* Start of day for this ha context. */
if ( peg_stuck ) {
/* Either we are the first or recovery in progress. */
qla82xx_rom_lock_recovery ( ha ) ;
goto dev_initialize ;
} else
/* Firmware already running. */
2010-04-12 17:59:55 -07:00
goto dev_ready ;
}
2010-09-07 20:55:32 -07:00
return rval ;
2010-04-12 17:59:55 -07:00
dev_initialize :
/* set to DEV_INITIALIZING */
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x009e ,
" HW State: INITIALIZING. \n " ) ;
2010-04-12 17:59:55 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE , QLA82XX_DEV_INITIALIZING ) ;
/* Driver that sets device state to initializating sets IDC version */
qla82xx_wr_32 ( ha , QLA82XX_CRB_DRV_IDC_VERSION , QLA82XX_IDC_VERSION ) ;
qla82xx_idc_unlock ( ha ) ;
rval = qla82xx_start_firmware ( vha ) ;
qla82xx_idc_lock ( ha ) ;
if ( rval ! = QLA_SUCCESS ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00ad ,
" HW State: FAILED. \n " ) ;
2010-04-12 17:59:55 -07:00
qla82xx_clear_drv_active ( ha ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE , QLA82XX_DEV_FAILED ) ;
return rval ;
}
dev_ready :
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x00ae ,
" HW State: READY. \n " ) ;
2010-04-12 17:59:55 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE , QLA82XX_DEV_READY ) ;
return QLA_SUCCESS ;
}
2010-12-21 16:00:14 -08:00
/*
* qla82xx_need_qsnt_handler
* Code to start quiescence sequence
*
* Note :
* IDC lock must be held upon entry
*
* Return : void
*/
static void
qla82xx_need_qsnt_handler ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t dev_state , drv_state , drv_active ;
unsigned long reset_timeout ;
if ( vha - > flags . online ) {
/*Block any further I/O and wait for pending cmnds to complete*/
qla82xx_quiescent_state_cleanup ( vha ) ;
}
/* Set the quiescence ready bit */
qla82xx_set_qsnt_ready ( ha ) ;
/*wait for 30 secs for other functions to ack */
reset_timeout = jiffies + ( 30 * HZ ) ;
drv_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
drv_active = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
/* Its 2 that is written when qsnt is acked, moving one bit */
drv_active = drv_active < < 0x01 ;
while ( drv_state ! = drv_active ) {
if ( time_after_eq ( jiffies , reset_timeout ) ) {
/* quiescence timeout, other functions didn't ack
* changing the state to DEV_READY
*/
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0xb023 ,
" %s : QUIESCENT TIMEOUT. \n " , QLA2XXX_DRIVER_NAME ) ;
ql_log ( ql_log_info , vha , 0xb024 ,
" DRV_ACTIVE:%d DRV_STATE:%d. \n " ,
drv_active , drv_state ) ;
2010-12-21 16:00:14 -08:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE ,
2011-07-14 12:00:13 -07:00
QLA82XX_DEV_READY ) ;
ql_log ( ql_log_info , vha , 0xb025 ,
" HW State: DEV_READY. \n " ) ;
2010-12-21 16:00:14 -08:00
qla82xx_idc_unlock ( ha ) ;
qla2x00_perform_loop_resync ( vha ) ;
qla82xx_idc_lock ( ha ) ;
qla82xx_clear_qsnt_ready ( vha ) ;
return ;
}
qla82xx_idc_unlock ( ha ) ;
msleep ( 1000 ) ;
qla82xx_idc_lock ( ha ) ;
drv_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
drv_active = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
drv_active = drv_active < < 0x01 ;
}
dev_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
/* everyone acked so set the state to DEV_QUIESCENCE */
if ( dev_state = = QLA82XX_DEV_NEED_QUIESCENT ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0xb026 ,
" HW State: DEV_QUIESCENT. \n " ) ;
2010-12-21 16:00:14 -08:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE , QLA82XX_DEV_QUIESCENT ) ;
}
}
/*
* qla82xx_wait_for_state_change
* Wait for device state to change from given current state
*
* Note :
* IDC lock must not be held upon entry
*
* Return :
* Changed device state .
*/
uint32_t
qla82xx_wait_for_state_change ( scsi_qla_host_t * vha , uint32_t curr_state )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t dev_state ;
do {
msleep ( 1000 ) ;
qla82xx_idc_lock ( ha ) ;
dev_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
qla82xx_idc_unlock ( ha ) ;
} while ( dev_state = = curr_state ) ;
return dev_state ;
}
2010-04-12 17:59:55 -07:00
static void
qla82xx_dev_failed_handler ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
/* Disable the board */
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x00b8 ,
" Disabling the board. \n " ) ;
2010-04-12 17:59:55 -07:00
2010-05-28 15:08:15 -07:00
qla82xx_idc_lock ( ha ) ;
qla82xx_clear_drv_active ( ha ) ;
qla82xx_idc_unlock ( ha ) ;
2010-04-12 17:59:55 -07:00
/* Set DEV_FAILED flag to disable timer */
vha - > device_flags | = DFLG_DEV_FAILED ;
qla2x00_abort_all_cmds ( vha , DID_NO_CONNECT < < 16 ) ;
qla2x00_mark_all_devices_lost ( vha , 0 ) ;
vha - > flags . online = 0 ;
vha - > flags . init_done = 0 ;
}
/*
* qla82xx_need_reset_handler
* Code to start reset sequence
*
* Note :
* IDC lock must be held upon entry
*
* Return :
* Success : 0
* Failed : 1
*/
static void
qla82xx_need_reset_handler ( scsi_qla_host_t * vha )
{
2011-08-16 11:31:55 -07:00
uint32_t dev_state , drv_state , drv_active ;
uint32_t active_mask = 0 ;
2010-04-12 17:59:55 -07:00
unsigned long reset_timeout ;
struct qla_hw_data * ha = vha - > hw ;
struct req_que * req = ha - > req_q_map [ 0 ] ;
if ( vha - > flags . online ) {
qla82xx_idc_unlock ( ha ) ;
qla2x00_abort_isp_cleanup ( vha ) ;
ha - > isp_ops - > get_flash_version ( vha , req - > ring ) ;
ha - > isp_ops - > nvram_config ( vha ) ;
qla82xx_idc_lock ( ha ) ;
}
2011-08-16 11:31:44 -07:00
drv_active = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
if ( ! ha - > flags . isp82xx_reset_owner ) {
ql_dbg ( ql_dbg_p3p , vha , 0xb028 ,
" reset_acknowledged by 0x%x \n " , ha - > portnum ) ;
qla82xx_set_rst_ready ( ha ) ;
} else {
active_mask = ~ ( QLA82XX_DRV_ACTIVE < < ( ha - > portnum * 4 ) ) ;
drv_active & = active_mask ;
ql_dbg ( ql_dbg_p3p , vha , 0xb029 ,
" active_mask: 0x%08x \n " , active_mask ) ;
}
2010-04-12 17:59:55 -07:00
/* wait for 10 seconds for reset ack from all functions */
reset_timeout = jiffies + ( ha - > nx_reset_timeout * HZ ) ;
drv_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
drv_active = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
2011-08-16 11:31:44 -07:00
dev_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
2010-04-12 17:59:55 -07:00
2011-08-16 11:31:44 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb02a ,
" drv_state: 0x%08x, drv_active: 0x%08x, "
" dev_state: 0x%08x, active_mask: 0x%08x \n " ,
drv_state , drv_active , dev_state , active_mask ) ;
while ( drv_state ! = drv_active & &
dev_state ! = QLA82XX_DEV_INITIALIZING ) {
2010-04-12 17:59:55 -07:00
if ( time_after_eq ( jiffies , reset_timeout ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x00b5 ,
" Reset timeout. \n " ) ;
2010-04-12 17:59:55 -07:00
break ;
}
qla82xx_idc_unlock ( ha ) ;
msleep ( 1000 ) ;
qla82xx_idc_lock ( ha ) ;
drv_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
drv_active = qla82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
2011-08-16 11:31:44 -07:00
if ( ha - > flags . isp82xx_reset_owner )
drv_active & = active_mask ;
dev_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
2010-04-12 17:59:55 -07:00
}
2011-08-16 11:31:44 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb02b ,
" drv_state: 0x%08x, drv_active: 0x%08x, "
" dev_state: 0x%08x, active_mask: 0x%08x \n " ,
drv_state , drv_active , dev_state , active_mask ) ;
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x00b6 ,
" Device state is 0x%x = %s. \n " ,
dev_state ,
2011-08-16 11:31:44 -07:00
dev_state < MAX_STATES ? qdev_state ( dev_state ) : " Unknown " ) ;
2010-05-04 15:01:34 -07:00
2010-04-12 17:59:55 -07:00
/* Force to DEV_COLD unless someone else is starting a reset */
2011-08-16 11:31:44 -07:00
if ( dev_state ! = QLA82XX_DEV_INITIALIZING & &
dev_state ! = QLA82XX_DEV_COLD ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x00b7 ,
" HW State: COLD/RE-INIT. \n " ) ;
2010-04-12 17:59:55 -07:00
qla82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE , QLA82XX_DEV_COLD ) ;
2011-08-16 11:31:44 -07:00
if ( ql2xmdenable ) {
if ( qla82xx_md_collect ( vha ) )
ql_log ( ql_log_warn , vha , 0xb02c ,
" Not able to collect minidump. \n " ) ;
} else
ql_log ( ql_log_warn , vha , 0xb04f ,
" Minidump disabled. \n " ) ;
2010-04-12 17:59:55 -07:00
}
}
2011-08-16 11:31:54 -07:00
int
2011-08-16 11:31:44 -07:00
qla82xx_check_md_needed ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
uint16_t fw_major_version , fw_minor_version , fw_subminor_version ;
2011-08-16 11:31:54 -07:00
int rval = QLA_SUCCESS ;
fw_major_version = ha - > fw_major_version ;
fw_minor_version = ha - > fw_minor_version ;
fw_subminor_version = ha - > fw_subminor_version ;
2012-02-09 11:15:34 -08:00
rval = qla2x00_get_fw_version ( vha ) ;
2011-08-16 11:31:54 -07:00
if ( rval ! = QLA_SUCCESS )
return rval ;
if ( ql2xmdenable ) {
if ( ! ha - > fw_dumped ) {
if ( fw_major_version ! = ha - > fw_major_version | |
fw_minor_version ! = ha - > fw_minor_version | |
fw_subminor_version ! = ha - > fw_subminor_version ) {
ql_log ( ql_log_info , vha , 0xb02d ,
" Firmware version differs "
" Previous version: %d:%d:%d - "
" New version: %d:%d:%d \n " ,
ha - > fw_major_version ,
ha - > fw_minor_version ,
ha - > fw_subminor_version ,
fw_major_version , fw_minor_version ,
fw_subminor_version ) ;
/* Release MiniDump resources */
qla82xx_md_free ( vha ) ;
/* ALlocate MiniDump resources */
qla82xx_md_prep ( vha ) ;
2011-11-18 09:03:15 -08:00
}
} else
ql_log ( ql_log_info , vha , 0xb02e ,
" Firmware dump available to retrieve \n " ) ;
2011-08-16 11:31:54 -07:00
}
return rval ;
2011-08-16 11:31:44 -07:00
}
2011-02-23 15:27:10 -08:00
int
2010-04-12 17:59:55 -07:00
qla82xx_check_fw_alive ( scsi_qla_host_t * vha )
{
2011-02-23 15:27:10 -08:00
uint32_t fw_heartbeat_counter ;
int status = 0 ;
2010-04-12 17:59:55 -07:00
2011-02-23 15:27:10 -08:00
fw_heartbeat_counter = qla82xx_rd_32 ( vha - > hw ,
QLA82XX_PEG_ALIVE_COUNTER ) ;
2010-09-03 15:20:50 -07:00
/* all 0xff, assume AER/EEH in progress, ignore */
2011-07-14 12:00:13 -07:00
if ( fw_heartbeat_counter = = 0xffffffff ) {
ql_dbg ( ql_dbg_timer , vha , 0x6003 ,
" FW heartbeat counter is 0xffffffff, "
" returning status=%d. \n " , status ) ;
2011-02-23 15:27:10 -08:00
return status ;
2011-07-14 12:00:13 -07:00
}
2010-04-12 17:59:55 -07:00
if ( vha - > fw_heartbeat_counter = = fw_heartbeat_counter ) {
vha - > seconds_since_last_heartbeat + + ;
/* FW not alive after 2 seconds */
if ( vha - > seconds_since_last_heartbeat = = 2 ) {
vha - > seconds_since_last_heartbeat = 0 ;
2011-02-23 15:27:10 -08:00
status = 1 ;
2010-04-12 17:59:55 -07:00
}
2010-09-03 14:57:02 -07:00
} else
vha - > seconds_since_last_heartbeat = 0 ;
2010-04-12 17:59:55 -07:00
vha - > fw_heartbeat_counter = fw_heartbeat_counter ;
2011-07-14 12:00:13 -07:00
if ( status )
ql_dbg ( ql_dbg_timer , vha , 0x6004 ,
" Returning status=%d. \n " , status ) ;
2011-02-23 15:27:10 -08:00
return status ;
2010-04-12 17:59:55 -07:00
}
/*
* qla82xx_device_state_handler
* Main state handler
*
* Note :
* IDC lock must be held upon entry
*
* Return :
* Success : 0
* Failed : 1
*/
int
qla82xx_device_state_handler ( scsi_qla_host_t * vha )
{
uint32_t dev_state ;
2011-03-30 11:46:30 -07:00
uint32_t old_dev_state ;
2010-04-12 17:59:55 -07:00
int rval = QLA_SUCCESS ;
unsigned long dev_init_timeout ;
struct qla_hw_data * ha = vha - > hw ;
2011-03-30 11:46:30 -07:00
int loopcount = 0 ;
2010-04-12 17:59:55 -07:00
qla82xx_idc_lock ( ha ) ;
if ( ! vha - > flags . init_done )
qla82xx_set_drv_active ( vha ) ;
2010-05-04 15:01:34 -07:00
dev_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
2011-03-30 11:46:30 -07:00
old_dev_state = dev_state ;
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x009b ,
" Device state is 0x%x = %s. \n " ,
dev_state ,
2011-08-16 11:31:44 -07:00
dev_state < MAX_STATES ? qdev_state ( dev_state ) : " Unknown " ) ;
2010-04-12 17:59:55 -07:00
/* wait for 30 seconds for device to go ready */
dev_init_timeout = jiffies + ( ha - > nx_dev_init_timeout * HZ ) ;
while ( 1 ) {
if ( time_after_eq ( jiffies , dev_init_timeout ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_fatal , vha , 0x009c ,
" Device init failed. \n " ) ;
2010-04-12 17:59:55 -07:00
rval = QLA_FUNCTION_FAILED ;
break ;
}
dev_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
2011-03-30 11:46:30 -07:00
if ( old_dev_state ! = dev_state ) {
loopcount = 0 ;
old_dev_state = dev_state ;
}
if ( loopcount < 5 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x009d ,
" Device state is 0x%x = %s. \n " ,
dev_state ,
2011-08-16 11:31:44 -07:00
dev_state < MAX_STATES ? qdev_state ( dev_state ) :
2011-07-14 12:00:13 -07:00
" Unknown " ) ;
2011-03-30 11:46:30 -07:00
}
2010-05-04 15:01:34 -07:00
2010-04-12 17:59:55 -07:00
switch ( dev_state ) {
case QLA82XX_DEV_READY :
2011-08-16 11:31:44 -07:00
ha - > flags . isp82xx_reset_owner = 0 ;
2010-04-12 17:59:55 -07:00
goto exit ;
case QLA82XX_DEV_COLD :
rval = qla82xx_device_bootstrap ( vha ) ;
2011-08-16 11:31:44 -07:00
break ;
2010-04-12 17:59:55 -07:00
case QLA82XX_DEV_INITIALIZING :
qla82xx_idc_unlock ( ha ) ;
msleep ( 1000 ) ;
qla82xx_idc_lock ( ha ) ;
break ;
case QLA82XX_DEV_NEED_RESET :
2011-08-16 11:31:46 -07:00
if ( ! ql2xdontresethba )
qla82xx_need_reset_handler ( vha ) ;
else {
qla82xx_idc_unlock ( ha ) ;
msleep ( 1000 ) ;
qla82xx_idc_lock ( ha ) ;
}
2011-02-23 15:27:08 -08:00
dev_init_timeout = jiffies +
2011-08-16 11:31:46 -07:00
( ha - > nx_dev_init_timeout * HZ ) ;
2010-04-12 17:59:55 -07:00
break ;
case QLA82XX_DEV_NEED_QUIESCENT :
2010-12-21 16:00:14 -08:00
qla82xx_need_qsnt_handler ( vha ) ;
/* Reset timeout value after quiescence handler */
dev_init_timeout = jiffies + ( ha - > nx_dev_init_timeout \
* HZ ) ;
break ;
2010-04-12 17:59:55 -07:00
case QLA82XX_DEV_QUIESCENT :
2010-12-21 16:00:14 -08:00
/* Owner will exit and other will wait for the state
* to get changed
*/
if ( ha - > flags . quiesce_owner )
goto exit ;
2010-04-12 17:59:55 -07:00
qla82xx_idc_unlock ( ha ) ;
msleep ( 1000 ) ;
qla82xx_idc_lock ( ha ) ;
2010-12-21 16:00:14 -08:00
/* Reset timeout value after quiescence handler */
dev_init_timeout = jiffies + ( ha - > nx_dev_init_timeout \
* HZ ) ;
2010-04-12 17:59:55 -07:00
break ;
case QLA82XX_DEV_FAILED :
qla82xx_dev_failed_handler ( vha ) ;
rval = QLA_FUNCTION_FAILED ;
goto exit ;
default :
qla82xx_idc_unlock ( ha ) ;
msleep ( 1000 ) ;
qla82xx_idc_lock ( ha ) ;
}
2011-03-30 11:46:30 -07:00
loopcount + + ;
2010-04-12 17:59:55 -07:00
}
exit :
qla82xx_idc_unlock ( ha ) ;
return rval ;
}
2011-11-18 09:02:17 -08:00
void qla82xx_clear_pending_mbx ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
if ( ha - > flags . mbox_busy ) {
ha - > flags . mbox_int = 1 ;
2011-11-18 09:02:18 -08:00
ha - > flags . mbox_busy = 0 ;
2011-11-18 09:02:17 -08:00
ql_log ( ql_log_warn , vha , 0x6010 ,
" Doing premature completion of mbx command. \n " ) ;
if ( test_bit ( MBX_INTR_WAIT , & ha - > mbx_cmd_flags ) )
complete ( & ha - > mbx_intr_comp ) ;
}
}
2010-04-12 17:59:55 -07:00
void qla82xx_watchdog ( scsi_qla_host_t * vha )
{
2011-02-23 15:27:10 -08:00
uint32_t dev_state , halt_status ;
2010-04-12 17:59:55 -07:00
struct qla_hw_data * ha = vha - > hw ;
/* don't poll if reset is going on */
2011-02-23 15:27:10 -08:00
if ( ! ha - > flags . isp82xx_reset_hdlr_active ) {
dev_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
if ( dev_state = = QLA82XX_DEV_NEED_RESET & &
! test_bit ( ISP_ABORT_NEEDED , & vha - > dpc_flags ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x6001 ,
" Adapter reset needed. \n " ) ;
2010-04-12 17:59:55 -07:00
set_bit ( ISP_ABORT_NEEDED , & vha - > dpc_flags ) ;
qla2xxx_wake_dpc ( vha ) ;
2010-12-21 16:00:14 -08:00
} else if ( dev_state = = QLA82XX_DEV_NEED_QUIESCENT & &
! test_bit ( ISP_QUIESCE_NEEDED , & vha - > dpc_flags ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x6002 ,
" Quiescent needed. \n " ) ;
2010-12-21 16:00:14 -08:00
set_bit ( ISP_QUIESCE_NEEDED , & vha - > dpc_flags ) ;
qla2xxx_wake_dpc ( vha ) ;
2010-04-12 17:59:55 -07:00
} else {
2011-02-23 15:27:10 -08:00
if ( qla82xx_check_fw_alive ( vha ) ) {
2011-11-18 09:02:19 -08:00
ql_dbg ( ql_dbg_timer , vha , 0x6011 ,
" disabling pause transmit on port 0 & 1. \n " ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0x98 ,
CRB_NIU_XG_PAUSE_CTL_P0 | CRB_NIU_XG_PAUSE_CTL_P1 ) ;
2011-02-23 15:27:10 -08:00
halt_status = qla82xx_rd_32 ( ha ,
QLA82XX_PEG_HALT_STATUS1 ) ;
2011-11-18 09:02:19 -08:00
ql_log ( ql_log_info , vha , 0x6005 ,
2011-07-14 12:00:13 -07:00
" dumping hw/fw registers:. \n "
" PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,. \n "
" PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,. \n "
" PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,. \n "
" PEG_NET_4_PC: 0x%x. \n " , halt_status ,
2011-03-30 11:46:28 -07:00
qla82xx_rd_32 ( ha , QLA82XX_PEG_HALT_STATUS2 ) ,
qla82xx_rd_32 ( ha ,
QLA82XX_CRB_PEG_NET_0 + 0x3c ) ,
qla82xx_rd_32 ( ha ,
QLA82XX_CRB_PEG_NET_1 + 0x3c ) ,
qla82xx_rd_32 ( ha ,
QLA82XX_CRB_PEG_NET_2 + 0x3c ) ,
qla82xx_rd_32 ( ha ,
QLA82XX_CRB_PEG_NET_3 + 0x3c ) ,
qla82xx_rd_32 ( ha ,
QLA82XX_CRB_PEG_NET_4 + 0x3c ) ) ;
2012-02-09 11:14:12 -08:00
if ( ( ( halt_status & 0x1fffff00 ) > > 8 ) = = 0x67 )
2011-11-18 09:02:16 -08:00
ql_log ( ql_log_warn , vha , 0xb052 ,
" Firmware aborted with "
" error code 0x00006700. Device is "
" being reset. \n " ) ;
2011-02-23 15:27:10 -08:00
if ( halt_status & HALT_STATUS_UNRECOVERABLE ) {
set_bit ( ISP_UNRECOVERABLE ,
& vha - > dpc_flags ) ;
} else {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha , 0x6006 ,
" Detect abort needed. \n " ) ;
2011-02-23 15:27:10 -08:00
set_bit ( ISP_ABORT_NEEDED ,
& vha - > dpc_flags ) ;
}
qla2xxx_wake_dpc ( vha ) ;
ha - > flags . isp82xx_fw_hung = 1 ;
2011-11-18 09:02:17 -08:00
ql_log ( ql_log_warn , vha , 0x6007 , " Firmware hung. \n " ) ;
qla82xx_clear_pending_mbx ( vha ) ;
2011-02-23 15:27:10 -08:00
}
2010-04-12 17:59:55 -07:00
}
}
}
int qla82xx_load_risc ( scsi_qla_host_t * vha , uint32_t * srisc_addr )
{
int rval ;
rval = qla82xx_device_state_handler ( vha ) ;
return rval ;
}
2011-08-16 11:31:44 -07:00
void
qla82xx_set_reset_owner ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t dev_state ;
dev_state = qla82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
if ( dev_state = = QLA82XX_DEV_READY ) {
ql_log ( ql_log_info , vha , 0xb02f ,
" HW State: NEED RESET \n " ) ;
qla82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE ,
QLA82XX_DEV_NEED_RESET ) ;
ha - > flags . isp82xx_reset_owner = 1 ;
ql_dbg ( ql_dbg_p3p , vha , 0xb030 ,
" reset_owner is 0x%x \n " , ha - > portnum ) ;
} else
ql_log ( ql_log_info , vha , 0xb031 ,
" Device state is 0x%x = %s. \n " ,
dev_state ,
dev_state < MAX_STATES ? qdev_state ( dev_state ) : " Unknown " ) ;
}
2010-04-12 17:59:55 -07:00
/*
* qla82xx_abort_isp
* Resets ISP and aborts all outstanding commands .
*
* Input :
* ha = adapter block pointer .
*
* Returns :
* 0 = success
*/
int
qla82xx_abort_isp ( scsi_qla_host_t * vha )
{
int rval ;
struct qla_hw_data * ha = vha - > hw ;
if ( vha - > device_flags & DFLG_DEV_FAILED ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x8024 ,
" Device in failed state, exiting. \n " ) ;
2010-04-12 17:59:55 -07:00
return QLA_SUCCESS ;
}
2011-02-23 15:27:10 -08:00
ha - > flags . isp82xx_reset_hdlr_active = 1 ;
2010-04-12 17:59:55 -07:00
qla82xx_idc_lock ( ha ) ;
2011-08-16 11:31:44 -07:00
qla82xx_set_reset_owner ( vha ) ;
2010-04-12 17:59:55 -07:00
qla82xx_idc_unlock ( ha ) ;
rval = qla82xx_device_state_handler ( vha ) ;
qla82xx_idc_lock ( ha ) ;
qla82xx_clear_rst_ready ( ha ) ;
qla82xx_idc_unlock ( ha ) ;
2010-05-28 15:08:25 -07:00
if ( rval = = QLA_SUCCESS ) {
2011-02-23 15:27:10 -08:00
ha - > flags . isp82xx_fw_hung = 0 ;
ha - > flags . isp82xx_reset_hdlr_active = 0 ;
2010-04-12 17:59:55 -07:00
qla82xx_restart_isp ( vha ) ;
2010-05-28 15:08:25 -07:00
}
2010-05-04 15:01:34 -07:00
if ( rval ) {
vha - > flags . online = 1 ;
if ( test_bit ( ISP_ABORT_RETRY , & vha - > dpc_flags ) ) {
if ( ha - > isp_abort_cnt = = 0 ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x8027 ,
" ISP error recover failed - board "
" disabled. \n " ) ;
2010-05-04 15:01:34 -07:00
/*
* The next call disables the board
* completely .
*/
ha - > isp_ops - > reset_adapter ( vha ) ;
vha - > flags . online = 0 ;
clear_bit ( ISP_ABORT_RETRY ,
& vha - > dpc_flags ) ;
rval = QLA_SUCCESS ;
} else { /* schedule another ISP abort */
ha - > isp_abort_cnt - - ;
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_warn , vha , 0x8036 ,
" ISP abort - retry remaining %d. \n " ,
ha - > isp_abort_cnt ) ;
2010-05-04 15:01:34 -07:00
rval = QLA_FUNCTION_FAILED ;
}
} else {
ha - > isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT ;
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_taskm , vha , 0x8029 ,
" ISP error recovery - retrying (%d) more times. \n " ,
ha - > isp_abort_cnt ) ;
2010-05-04 15:01:34 -07:00
set_bit ( ISP_ABORT_RETRY , & vha - > dpc_flags ) ;
rval = QLA_FUNCTION_FAILED ;
}
}
2010-04-12 17:59:55 -07:00
return rval ;
}
/*
* qla82xx_fcoe_ctx_reset
* Perform a quick reset and aborts all outstanding commands .
* This will only perform an FCoE context reset and avoids a full blown
* chip reset .
*
* Input :
* ha = adapter block pointer .
* is_reset_path = flag for identifying the reset path .
*
* Returns :
* 0 = success
*/
int qla82xx_fcoe_ctx_reset ( scsi_qla_host_t * vha )
{
int rval = QLA_FUNCTION_FAILED ;
if ( vha - > flags . online ) {
/* Abort all outstanding commands, so as to be requeued later */
qla2x00_abort_isp_cleanup ( vha ) ;
}
/* Stop currently executing firmware.
* This will destroy existing FCoE context at the F / W end .
*/
qla2x00_try_to_stop_firmware ( vha ) ;
/* Restart. Creates a new FCoE context on INIT_FIRMWARE. */
rval = qla82xx_restart_isp ( vha ) ;
return rval ;
}
/*
* qla2x00_wait_for_fcoe_ctx_reset
* Wait till the FCoE context is reset .
*
* Note :
* Does context switching here .
* Release SPIN_LOCK ( if any ) before calling this routine .
*
* Return :
* Success ( fcoe_ctx reset is done ) : 0
* Failed ( fcoe_ctx reset not completed within max loop timout ) : 1
*/
int qla2x00_wait_for_fcoe_ctx_reset ( scsi_qla_host_t * vha )
{
int status = QLA_FUNCTION_FAILED ;
unsigned long wait_reset ;
wait_reset = jiffies + ( MAX_LOOP_TIMEOUT * HZ ) ;
while ( ( test_bit ( FCOE_CTX_RESET_NEEDED , & vha - > dpc_flags ) | |
test_bit ( ABORT_ISP_ACTIVE , & vha - > dpc_flags ) )
& & time_before ( jiffies , wait_reset ) ) {
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
schedule_timeout ( HZ ) ;
if ( ! test_bit ( FCOE_CTX_RESET_NEEDED , & vha - > dpc_flags ) & &
! test_bit ( ABORT_ISP_ACTIVE , & vha - > dpc_flags ) ) {
status = QLA_SUCCESS ;
break ;
}
}
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_p3p , vha , 0xb027 ,
2011-11-18 09:03:06 -08:00
" %s: status=%d. \n " , __func__ , status ) ;
2010-04-12 17:59:55 -07:00
return status ;
}
2011-02-23 15:27:10 -08:00
void
qla82xx_chip_reset_cleanup ( scsi_qla_host_t * vha )
{
int i ;
unsigned long flags ;
struct qla_hw_data * ha = vha - > hw ;
/* Check if 82XX firmware is alive or not
* We may have arrived here from NEED_RESET
* detection only
*/
if ( ! ha - > flags . isp82xx_fw_hung ) {
for ( i = 0 ; i < 2 ; i + + ) {
msleep ( 1000 ) ;
if ( qla82xx_check_fw_alive ( vha ) ) {
ha - > flags . isp82xx_fw_hung = 1 ;
2011-11-18 09:02:17 -08:00
qla82xx_clear_pending_mbx ( vha ) ;
2011-02-23 15:27:10 -08:00
break ;
}
}
}
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_init , vha , 0x00b0 ,
" Entered %s fw_hung=%d. \n " ,
__func__ , ha - > flags . isp82xx_fw_hung ) ;
2011-02-23 15:27:10 -08:00
/* Abort all commands gracefully if fw NOT hung */
if ( ! ha - > flags . isp82xx_fw_hung ) {
int cnt , que ;
srb_t * sp ;
struct req_que * req ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
for ( que = 0 ; que < ha - > max_req_queues ; que + + ) {
req = ha - > req_q_map [ que ] ;
if ( ! req )
continue ;
for ( cnt = 1 ; cnt < MAX_OUTSTANDING_COMMANDS ; cnt + + ) {
sp = req - > outstanding_cmds [ cnt ] ;
if ( sp ) {
2012-02-09 11:15:36 -08:00
if ( ! sp - > u . scmd . ctx | |
2011-02-23 15:27:10 -08:00
( sp - > flags & SRB_FCP_CMND_DMA_VALID ) ) {
spin_unlock_irqrestore (
& ha - > hardware_lock , flags ) ;
if ( ha - > isp_ops - > abort_command ( sp ) ) {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha ,
0x00b1 ,
" mbx abort failed. \n " ) ;
2011-02-23 15:27:10 -08:00
} else {
2011-07-14 12:00:13 -07:00
ql_log ( ql_log_info , vha ,
0x00b2 ,
" mbx abort success. \n " ) ;
2011-02-23 15:27:10 -08:00
}
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
}
}
}
}
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
/* Wait for pending cmds (physical and virtual) to complete */
if ( ! qla2x00_eh_wait_for_pending_commands ( vha , 0 , 0 ,
WAIT_HOST ) = = QLA_SUCCESS ) {
2011-07-14 12:00:13 -07:00
ql_dbg ( ql_dbg_init , vha , 0x00b3 ,
" Done wait for "
" pending commands. \n " ) ;
2011-02-23 15:27:10 -08:00
}
}
}
2011-08-16 11:31:44 -07:00
/* Minidump related functions */
static int
qla82xx_minidump_process_control ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , uint32_t * * d_ptr )
{
struct qla_hw_data * ha = vha - > hw ;
struct qla82xx_md_entry_crb * crb_entry ;
uint32_t read_value , opcode , poll_time ;
uint32_t addr , index , crb_addr ;
unsigned long wtime ;
struct qla82xx_md_template_hdr * tmplt_hdr ;
uint32_t rval = QLA_SUCCESS ;
int i ;
tmplt_hdr = ( struct qla82xx_md_template_hdr * ) ha - > md_tmplt_hdr ;
crb_entry = ( struct qla82xx_md_entry_crb * ) entry_hdr ;
crb_addr = crb_entry - > addr ;
for ( i = 0 ; i < crb_entry - > op_count ; i + + ) {
opcode = crb_entry - > crb_ctrl . opcode ;
if ( opcode & QLA82XX_DBG_OPCODE_WR ) {
qla82xx_md_rw_32 ( ha , crb_addr ,
crb_entry - > value_1 , 1 ) ;
opcode & = ~ QLA82XX_DBG_OPCODE_WR ;
}
if ( opcode & QLA82XX_DBG_OPCODE_RW ) {
read_value = qla82xx_md_rw_32 ( ha , crb_addr , 0 , 0 ) ;
qla82xx_md_rw_32 ( ha , crb_addr , read_value , 1 ) ;
opcode & = ~ QLA82XX_DBG_OPCODE_RW ;
}
if ( opcode & QLA82XX_DBG_OPCODE_AND ) {
read_value = qla82xx_md_rw_32 ( ha , crb_addr , 0 , 0 ) ;
read_value & = crb_entry - > value_2 ;
opcode & = ~ QLA82XX_DBG_OPCODE_AND ;
if ( opcode & QLA82XX_DBG_OPCODE_OR ) {
read_value | = crb_entry - > value_3 ;
opcode & = ~ QLA82XX_DBG_OPCODE_OR ;
}
qla82xx_md_rw_32 ( ha , crb_addr , read_value , 1 ) ;
}
if ( opcode & QLA82XX_DBG_OPCODE_OR ) {
read_value = qla82xx_md_rw_32 ( ha , crb_addr , 0 , 0 ) ;
read_value | = crb_entry - > value_3 ;
qla82xx_md_rw_32 ( ha , crb_addr , read_value , 1 ) ;
opcode & = ~ QLA82XX_DBG_OPCODE_OR ;
}
if ( opcode & QLA82XX_DBG_OPCODE_POLL ) {
poll_time = crb_entry - > crb_strd . poll_timeout ;
wtime = jiffies + poll_time ;
read_value = qla82xx_md_rw_32 ( ha , crb_addr , 0 , 0 ) ;
do {
if ( ( read_value & crb_entry - > value_2 )
= = crb_entry - > value_1 )
break ;
else if ( time_after_eq ( jiffies , wtime ) ) {
/* capturing dump failed */
rval = QLA_FUNCTION_FAILED ;
break ;
} else
read_value = qla82xx_md_rw_32 ( ha ,
crb_addr , 0 , 0 ) ;
} while ( 1 ) ;
opcode & = ~ QLA82XX_DBG_OPCODE_POLL ;
}
if ( opcode & QLA82XX_DBG_OPCODE_RDSTATE ) {
if ( crb_entry - > crb_strd . state_index_a ) {
index = crb_entry - > crb_strd . state_index_a ;
addr = tmplt_hdr - > saved_state_array [ index ] ;
} else
addr = crb_addr ;
read_value = qla82xx_md_rw_32 ( ha , addr , 0 , 0 ) ;
index = crb_entry - > crb_ctrl . state_index_v ;
tmplt_hdr - > saved_state_array [ index ] = read_value ;
opcode & = ~ QLA82XX_DBG_OPCODE_RDSTATE ;
}
if ( opcode & QLA82XX_DBG_OPCODE_WRSTATE ) {
if ( crb_entry - > crb_strd . state_index_a ) {
index = crb_entry - > crb_strd . state_index_a ;
addr = tmplt_hdr - > saved_state_array [ index ] ;
} else
addr = crb_addr ;
if ( crb_entry - > crb_ctrl . state_index_v ) {
index = crb_entry - > crb_ctrl . state_index_v ;
read_value =
tmplt_hdr - > saved_state_array [ index ] ;
} else
read_value = crb_entry - > value_1 ;
qla82xx_md_rw_32 ( ha , addr , read_value , 1 ) ;
opcode & = ~ QLA82XX_DBG_OPCODE_WRSTATE ;
}
if ( opcode & QLA82XX_DBG_OPCODE_MDSTATE ) {
index = crb_entry - > crb_ctrl . state_index_v ;
read_value = tmplt_hdr - > saved_state_array [ index ] ;
read_value < < = crb_entry - > crb_ctrl . shl ;
read_value > > = crb_entry - > crb_ctrl . shr ;
if ( crb_entry - > value_2 )
read_value & = crb_entry - > value_2 ;
read_value | = crb_entry - > value_3 ;
read_value + = crb_entry - > value_1 ;
tmplt_hdr - > saved_state_array [ index ] = read_value ;
opcode & = ~ QLA82XX_DBG_OPCODE_MDSTATE ;
}
crb_addr + = crb_entry - > crb_strd . addr_stride ;
}
return rval ;
}
static void
qla82xx_minidump_process_rdocm ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , uint32_t * * d_ptr )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t r_addr , r_stride , loop_cnt , i , r_value ;
struct qla82xx_md_entry_rdocm * ocm_hdr ;
uint32_t * data_ptr = * d_ptr ;
ocm_hdr = ( struct qla82xx_md_entry_rdocm * ) entry_hdr ;
r_addr = ocm_hdr - > read_addr ;
r_stride = ocm_hdr - > read_addr_stride ;
loop_cnt = ocm_hdr - > op_count ;
for ( i = 0 ; i < loop_cnt ; i + + ) {
r_value = RD_REG_DWORD ( ( void * ) ( r_addr + ha - > nx_pcibase ) ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
r_addr + = r_stride ;
}
* d_ptr = data_ptr ;
}
static void
qla82xx_minidump_process_rdmux ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , uint32_t * * d_ptr )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t r_addr , s_stride , s_addr , s_value , loop_cnt , i , r_value ;
struct qla82xx_md_entry_mux * mux_hdr ;
uint32_t * data_ptr = * d_ptr ;
mux_hdr = ( struct qla82xx_md_entry_mux * ) entry_hdr ;
r_addr = mux_hdr - > read_addr ;
s_addr = mux_hdr - > select_addr ;
s_stride = mux_hdr - > select_value_stride ;
s_value = mux_hdr - > select_value ;
loop_cnt = mux_hdr - > op_count ;
for ( i = 0 ; i < loop_cnt ; i + + ) {
qla82xx_md_rw_32 ( ha , s_addr , s_value , 1 ) ;
r_value = qla82xx_md_rw_32 ( ha , r_addr , 0 , 0 ) ;
* data_ptr + + = cpu_to_le32 ( s_value ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
s_value + = s_stride ;
}
* d_ptr = data_ptr ;
}
static void
qla82xx_minidump_process_rdcrb ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , uint32_t * * d_ptr )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t r_addr , r_stride , loop_cnt , i , r_value ;
struct qla82xx_md_entry_crb * crb_hdr ;
uint32_t * data_ptr = * d_ptr ;
crb_hdr = ( struct qla82xx_md_entry_crb * ) entry_hdr ;
r_addr = crb_hdr - > addr ;
r_stride = crb_hdr - > crb_strd . addr_stride ;
loop_cnt = crb_hdr - > op_count ;
for ( i = 0 ; i < loop_cnt ; i + + ) {
r_value = qla82xx_md_rw_32 ( ha , r_addr , 0 , 0 ) ;
* data_ptr + + = cpu_to_le32 ( r_addr ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
r_addr + = r_stride ;
}
* d_ptr = data_ptr ;
}
static int
qla82xx_minidump_process_l2tag ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , uint32_t * * d_ptr )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t addr , r_addr , c_addr , t_r_addr ;
uint32_t i , k , loop_count , t_value , r_cnt , r_value ;
unsigned long p_wait , w_time , p_mask ;
uint32_t c_value_w , c_value_r ;
struct qla82xx_md_entry_cache * cache_hdr ;
int rval = QLA_FUNCTION_FAILED ;
uint32_t * data_ptr = * d_ptr ;
cache_hdr = ( struct qla82xx_md_entry_cache * ) entry_hdr ;
loop_count = cache_hdr - > op_count ;
r_addr = cache_hdr - > read_addr ;
c_addr = cache_hdr - > control_addr ;
c_value_w = cache_hdr - > cache_ctrl . write_value ;
t_r_addr = cache_hdr - > tag_reg_addr ;
t_value = cache_hdr - > addr_ctrl . init_tag_value ;
r_cnt = cache_hdr - > read_ctrl . read_addr_cnt ;
p_wait = cache_hdr - > cache_ctrl . poll_wait ;
p_mask = cache_hdr - > cache_ctrl . poll_mask ;
for ( i = 0 ; i < loop_count ; i + + ) {
qla82xx_md_rw_32 ( ha , t_r_addr , t_value , 1 ) ;
if ( c_value_w )
qla82xx_md_rw_32 ( ha , c_addr , c_value_w , 1 ) ;
if ( p_mask ) {
w_time = jiffies + p_wait ;
do {
c_value_r = qla82xx_md_rw_32 ( ha , c_addr , 0 , 0 ) ;
if ( ( c_value_r & p_mask ) = = 0 )
break ;
else if ( time_after_eq ( jiffies , w_time ) ) {
/* capturing dump failed */
ql_dbg ( ql_dbg_p3p , vha , 0xb032 ,
" c_value_r: 0x%x, poll_mask: 0x%lx, "
" w_time: 0x%lx \n " ,
c_value_r , p_mask , w_time ) ;
return rval ;
}
} while ( 1 ) ;
}
addr = r_addr ;
for ( k = 0 ; k < r_cnt ; k + + ) {
r_value = qla82xx_md_rw_32 ( ha , addr , 0 , 0 ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
addr + = cache_hdr - > read_ctrl . read_addr_stride ;
}
t_value + = cache_hdr - > addr_ctrl . tag_value_stride ;
}
* d_ptr = data_ptr ;
return QLA_SUCCESS ;
}
static void
qla82xx_minidump_process_l1cache ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , uint32_t * * d_ptr )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t addr , r_addr , c_addr , t_r_addr ;
uint32_t i , k , loop_count , t_value , r_cnt , r_value ;
uint32_t c_value_w ;
struct qla82xx_md_entry_cache * cache_hdr ;
uint32_t * data_ptr = * d_ptr ;
cache_hdr = ( struct qla82xx_md_entry_cache * ) entry_hdr ;
loop_count = cache_hdr - > op_count ;
r_addr = cache_hdr - > read_addr ;
c_addr = cache_hdr - > control_addr ;
c_value_w = cache_hdr - > cache_ctrl . write_value ;
t_r_addr = cache_hdr - > tag_reg_addr ;
t_value = cache_hdr - > addr_ctrl . init_tag_value ;
r_cnt = cache_hdr - > read_ctrl . read_addr_cnt ;
for ( i = 0 ; i < loop_count ; i + + ) {
qla82xx_md_rw_32 ( ha , t_r_addr , t_value , 1 ) ;
qla82xx_md_rw_32 ( ha , c_addr , c_value_w , 1 ) ;
addr = r_addr ;
for ( k = 0 ; k < r_cnt ; k + + ) {
r_value = qla82xx_md_rw_32 ( ha , addr , 0 , 0 ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
addr + = cache_hdr - > read_ctrl . read_addr_stride ;
}
t_value + = cache_hdr - > addr_ctrl . tag_value_stride ;
}
* d_ptr = data_ptr ;
}
static void
qla82xx_minidump_process_queue ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , uint32_t * * d_ptr )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t s_addr , r_addr ;
uint32_t r_stride , r_value , r_cnt , qid = 0 ;
uint32_t i , k , loop_cnt ;
struct qla82xx_md_entry_queue * q_hdr ;
uint32_t * data_ptr = * d_ptr ;
q_hdr = ( struct qla82xx_md_entry_queue * ) entry_hdr ;
s_addr = q_hdr - > select_addr ;
r_cnt = q_hdr - > rd_strd . read_addr_cnt ;
r_stride = q_hdr - > rd_strd . read_addr_stride ;
loop_cnt = q_hdr - > op_count ;
for ( i = 0 ; i < loop_cnt ; i + + ) {
qla82xx_md_rw_32 ( ha , s_addr , qid , 1 ) ;
r_addr = q_hdr - > read_addr ;
for ( k = 0 ; k < r_cnt ; k + + ) {
r_value = qla82xx_md_rw_32 ( ha , r_addr , 0 , 0 ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
r_addr + = r_stride ;
}
qid + = q_hdr - > q_strd . queue_id_stride ;
}
* d_ptr = data_ptr ;
}
static void
qla82xx_minidump_process_rdrom ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , uint32_t * * d_ptr )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t r_addr , r_value ;
uint32_t i , loop_cnt ;
struct qla82xx_md_entry_rdrom * rom_hdr ;
uint32_t * data_ptr = * d_ptr ;
rom_hdr = ( struct qla82xx_md_entry_rdrom * ) entry_hdr ;
r_addr = rom_hdr - > read_addr ;
loop_cnt = rom_hdr - > read_data_size / sizeof ( uint32_t ) ;
for ( i = 0 ; i < loop_cnt ; i + + ) {
qla82xx_md_rw_32 ( ha , MD_DIRECT_ROM_WINDOW ,
( r_addr & 0xFFFF0000 ) , 1 ) ;
r_value = qla82xx_md_rw_32 ( ha ,
MD_DIRECT_ROM_READ_BASE +
( r_addr & 0x0000FFFF ) , 0 , 0 ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
r_addr + = sizeof ( uint32_t ) ;
}
* d_ptr = data_ptr ;
}
static int
qla82xx_minidump_process_rdmem ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , uint32_t * * d_ptr )
{
struct qla_hw_data * ha = vha - > hw ;
uint32_t r_addr , r_value , r_data ;
uint32_t i , j , loop_cnt ;
struct qla82xx_md_entry_rdmem * m_hdr ;
unsigned long flags ;
int rval = QLA_FUNCTION_FAILED ;
uint32_t * data_ptr = * d_ptr ;
m_hdr = ( struct qla82xx_md_entry_rdmem * ) entry_hdr ;
r_addr = m_hdr - > read_addr ;
loop_cnt = m_hdr - > read_data_size / 16 ;
if ( r_addr & 0xf ) {
ql_log ( ql_log_warn , vha , 0xb033 ,
" Read addr 0x%x not 16 bytes alligned \n " , r_addr ) ;
return rval ;
}
if ( m_hdr - > read_data_size % 16 ) {
ql_log ( ql_log_warn , vha , 0xb034 ,
" Read data[0x%x] not multiple of 16 bytes \n " ,
m_hdr - > read_data_size ) ;
return rval ;
}
ql_dbg ( ql_dbg_p3p , vha , 0xb035 ,
" [%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x \n " ,
__func__ , r_addr , m_hdr - > read_data_size , loop_cnt ) ;
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
for ( i = 0 ; i < loop_cnt ; i + + ) {
qla82xx_md_rw_32 ( ha , MD_MIU_TEST_AGT_ADDR_LO , r_addr , 1 ) ;
r_value = 0 ;
qla82xx_md_rw_32 ( ha , MD_MIU_TEST_AGT_ADDR_HI , r_value , 1 ) ;
r_value = MIU_TA_CTL_ENABLE ;
qla82xx_md_rw_32 ( ha , MD_MIU_TEST_AGT_CTRL , r_value , 1 ) ;
r_value = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE ;
qla82xx_md_rw_32 ( ha , MD_MIU_TEST_AGT_CTRL , r_value , 1 ) ;
for ( j = 0 ; j < MAX_CTL_CHECK ; j + + ) {
r_value = qla82xx_md_rw_32 ( ha ,
MD_MIU_TEST_AGT_CTRL , 0 , 0 ) ;
if ( ( r_value & MIU_TA_CTL_BUSY ) = = 0 )
break ;
}
if ( j > = MAX_CTL_CHECK ) {
printk_ratelimited ( KERN_ERR
" failed to read through agent \n " ) ;
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
return rval ;
}
for ( j = 0 ; j < 4 ; j + + ) {
r_data = qla82xx_md_rw_32 ( ha ,
MD_MIU_TEST_AGT_RDDATA [ j ] , 0 , 0 ) ;
* data_ptr + + = cpu_to_le32 ( r_data ) ;
}
r_addr + = 16 ;
}
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
* d_ptr = data_ptr ;
return QLA_SUCCESS ;
}
static int
qla82xx_validate_template_chksum ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
uint64_t chksum = 0 ;
uint32_t * d_ptr = ( uint32_t * ) ha - > md_tmplt_hdr ;
int count = ha - > md_template_size / sizeof ( uint32_t ) ;
while ( count - - > 0 )
chksum + = * d_ptr + + ;
while ( chksum > > 32 )
chksum = ( chksum & 0xFFFFFFFF ) + ( chksum > > 32 ) ;
return ~ chksum ;
}
static void
qla82xx_mark_entry_skipped ( scsi_qla_host_t * vha ,
qla82xx_md_entry_hdr_t * entry_hdr , int index )
{
entry_hdr - > d_ctrl . driver_flags | = QLA82XX_DBG_SKIPPED_FLAG ;
ql_dbg ( ql_dbg_p3p , vha , 0xb036 ,
" Skipping entry[%d]: "
" ETYPE[0x%x]-ELEVEL[0x%x] \n " ,
index , entry_hdr - > entry_type ,
entry_hdr - > d_ctrl . entry_capture_mask ) ;
}
int
qla82xx_md_collect ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
int no_entry_hdr = 0 ;
qla82xx_md_entry_hdr_t * entry_hdr ;
struct qla82xx_md_template_hdr * tmplt_hdr ;
uint32_t * data_ptr ;
uint32_t total_data_size = 0 , f_capture_mask , data_collected = 0 ;
int i = 0 , rval = QLA_FUNCTION_FAILED ;
tmplt_hdr = ( struct qla82xx_md_template_hdr * ) ha - > md_tmplt_hdr ;
data_ptr = ( uint32_t * ) ha - > md_dump ;
if ( ha - > fw_dumped ) {
ql_log ( ql_log_info , vha , 0xb037 ,
" Firmware dump available to retrive \n " ) ;
goto md_failed ;
}
ha - > fw_dumped = 0 ;
if ( ! ha - > md_tmplt_hdr | | ! ha - > md_dump ) {
ql_log ( ql_log_warn , vha , 0xb038 ,
" Memory not allocated for minidump capture \n " ) ;
goto md_failed ;
}
if ( qla82xx_validate_template_chksum ( vha ) ) {
ql_log ( ql_log_info , vha , 0xb039 ,
" Template checksum validation error \n " ) ;
goto md_failed ;
}
no_entry_hdr = tmplt_hdr - > num_of_entries ;
ql_dbg ( ql_dbg_p3p , vha , 0xb03a ,
" No of entry headers in Template: 0x%x \n " , no_entry_hdr ) ;
ql_dbg ( ql_dbg_p3p , vha , 0xb03b ,
" Capture Mask obtained: 0x%x \n " , tmplt_hdr - > capture_debug_level ) ;
f_capture_mask = tmplt_hdr - > capture_debug_level & 0xFF ;
/* Validate whether required debug level is set */
if ( ( f_capture_mask & 0x3 ) ! = 0x3 ) {
ql_log ( ql_log_warn , vha , 0xb03c ,
" Minimum required capture mask[0x%x] level not set \n " ,
f_capture_mask ) ;
goto md_failed ;
}
tmplt_hdr - > driver_capture_mask = ql2xmdcapmask ;
tmplt_hdr - > driver_info [ 0 ] = vha - > host_no ;
tmplt_hdr - > driver_info [ 1 ] = ( QLA_DRIVER_MAJOR_VER < < 24 ) |
( QLA_DRIVER_MINOR_VER < < 16 ) | ( QLA_DRIVER_PATCH_VER < < 8 ) |
QLA_DRIVER_BETA_VER ;
total_data_size = ha - > md_dump_size ;
2012-02-09 11:15:49 -08:00
ql_dbg ( ql_dbg_p3p , vha , 0xb03d ,
2011-08-16 11:31:44 -07:00
" Total minidump data_size 0x%x to be captured \n " , total_data_size ) ;
/* Check whether template obtained is valid */
if ( tmplt_hdr - > entry_type ! = QLA82XX_TLHDR ) {
ql_log ( ql_log_warn , vha , 0xb04e ,
" Bad template header entry type: 0x%x obtained \n " ,
tmplt_hdr - > entry_type ) ;
goto md_failed ;
}
entry_hdr = ( qla82xx_md_entry_hdr_t * ) \
( ( ( uint8_t * ) ha - > md_tmplt_hdr ) + tmplt_hdr - > first_entry_offset ) ;
/* Walk through the entry headers */
for ( i = 0 ; i < no_entry_hdr ; i + + ) {
if ( data_collected > total_data_size ) {
ql_log ( ql_log_warn , vha , 0xb03e ,
" More MiniDump data collected: [0x%x] \n " ,
data_collected ) ;
goto md_failed ;
}
if ( ! ( entry_hdr - > d_ctrl . entry_capture_mask &
ql2xmdcapmask ) ) {
entry_hdr - > d_ctrl . driver_flags | =
QLA82XX_DBG_SKIPPED_FLAG ;
ql_dbg ( ql_dbg_p3p , vha , 0xb03f ,
" Skipping entry[%d]: "
" ETYPE[0x%x]-ELEVEL[0x%x] \n " ,
i , entry_hdr - > entry_type ,
entry_hdr - > d_ctrl . entry_capture_mask ) ;
goto skip_nxt_entry ;
}
ql_dbg ( ql_dbg_p3p , vha , 0xb040 ,
" [%s]: data ptr[%d]: %p, entry_hdr: %p \n "
" entry_type: 0x%x, captrue_mask: 0x%x \n " ,
__func__ , i , data_ptr , entry_hdr ,
entry_hdr - > entry_type ,
entry_hdr - > d_ctrl . entry_capture_mask ) ;
ql_dbg ( ql_dbg_p3p , vha , 0xb041 ,
" Data collected: [0x%x], Dump size left:[0x%x] \n " ,
data_collected , ( ha - > md_dump_size - data_collected ) ) ;
/* Decode the entry type and take
* required action to capture debug data */
switch ( entry_hdr - > entry_type ) {
case QLA82XX_RDEND :
qla82xx_mark_entry_skipped ( vha , entry_hdr , i ) ;
break ;
case QLA82XX_CNTRL :
rval = qla82xx_minidump_process_control ( vha ,
entry_hdr , & data_ptr ) ;
if ( rval ! = QLA_SUCCESS ) {
qla82xx_mark_entry_skipped ( vha , entry_hdr , i ) ;
goto md_failed ;
}
break ;
case QLA82XX_RDCRB :
qla82xx_minidump_process_rdcrb ( vha ,
entry_hdr , & data_ptr ) ;
break ;
case QLA82XX_RDMEM :
rval = qla82xx_minidump_process_rdmem ( vha ,
entry_hdr , & data_ptr ) ;
if ( rval ! = QLA_SUCCESS ) {
qla82xx_mark_entry_skipped ( vha , entry_hdr , i ) ;
goto md_failed ;
}
break ;
case QLA82XX_BOARD :
case QLA82XX_RDROM :
qla82xx_minidump_process_rdrom ( vha ,
entry_hdr , & data_ptr ) ;
break ;
case QLA82XX_L2DTG :
case QLA82XX_L2ITG :
case QLA82XX_L2DAT :
case QLA82XX_L2INS :
rval = qla82xx_minidump_process_l2tag ( vha ,
entry_hdr , & data_ptr ) ;
if ( rval ! = QLA_SUCCESS ) {
qla82xx_mark_entry_skipped ( vha , entry_hdr , i ) ;
goto md_failed ;
}
break ;
case QLA82XX_L1DAT :
case QLA82XX_L1INS :
qla82xx_minidump_process_l1cache ( vha ,
entry_hdr , & data_ptr ) ;
break ;
case QLA82XX_RDOCM :
qla82xx_minidump_process_rdocm ( vha ,
entry_hdr , & data_ptr ) ;
break ;
case QLA82XX_RDMUX :
qla82xx_minidump_process_rdmux ( vha ,
entry_hdr , & data_ptr ) ;
break ;
case QLA82XX_QUEUE :
qla82xx_minidump_process_queue ( vha ,
entry_hdr , & data_ptr ) ;
break ;
case QLA82XX_RDNOP :
default :
qla82xx_mark_entry_skipped ( vha , entry_hdr , i ) ;
break ;
}
ql_dbg ( ql_dbg_p3p , vha , 0xb042 ,
" [%s]: data ptr[%d]: %p \n " , __func__ , i , data_ptr ) ;
data_collected = ( uint8_t * ) data_ptr -
( uint8_t * ) ha - > md_dump ;
skip_nxt_entry :
entry_hdr = ( qla82xx_md_entry_hdr_t * ) \
( ( ( uint8_t * ) entry_hdr ) + entry_hdr - > entry_size ) ;
}
if ( data_collected ! = total_data_size ) {
2012-02-09 11:15:49 -08:00
ql_dbg ( ql_dbg_p3p , vha , 0xb043 ,
2011-08-16 11:31:44 -07:00
" MiniDump data mismatch: Data collected: [0x%x], "
" total_data_size:[0x%x] \n " ,
data_collected , total_data_size ) ;
goto md_failed ;
}
ql_log ( ql_log_info , vha , 0xb044 ,
" Firmware dump saved to temp buffer (%ld/%p %ld/%p). \n " ,
vha - > host_no , ha - > md_tmplt_hdr , vha - > host_no , ha - > md_dump ) ;
ha - > fw_dumped = 1 ;
qla2x00_post_uevent_work ( vha , QLA_UEVENT_CODE_FW_DUMP ) ;
md_failed :
return rval ;
}
int
qla82xx_md_alloc ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
int i , k ;
struct qla82xx_md_template_hdr * tmplt_hdr ;
tmplt_hdr = ( struct qla82xx_md_template_hdr * ) ha - > md_tmplt_hdr ;
if ( ql2xmdcapmask < 0x3 | | ql2xmdcapmask > 0x7F ) {
ql2xmdcapmask = tmplt_hdr - > capture_debug_level & 0xFF ;
ql_log ( ql_log_info , vha , 0xb045 ,
" Forcing driver capture mask to firmware default capture mask: 0x%x. \n " ,
ql2xmdcapmask ) ;
}
for ( i = 0x2 , k = 1 ; ( i & QLA82XX_DEFAULT_CAP_MASK ) ; i < < = 1 , k + + ) {
if ( i & ql2xmdcapmask )
ha - > md_dump_size + = tmplt_hdr - > capture_size_array [ k ] ;
}
if ( ha - > md_dump ) {
ql_log ( ql_log_warn , vha , 0xb046 ,
" Firmware dump previously allocated. \n " ) ;
return 1 ;
}
ha - > md_dump = vmalloc ( ha - > md_dump_size ) ;
if ( ha - > md_dump = = NULL ) {
ql_log ( ql_log_warn , vha , 0xb047 ,
" Unable to allocate memory for Minidump size "
" (0x%x). \n " , ha - > md_dump_size ) ;
return 1 ;
}
return 0 ;
}
void
qla82xx_md_free ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
/* Release the template header allocated */
if ( ha - > md_tmplt_hdr ) {
ql_log ( ql_log_info , vha , 0xb048 ,
" Free MiniDump template: %p, size (%d KB) \n " ,
ha - > md_tmplt_hdr , ha - > md_template_size / 1024 ) ;
dma_free_coherent ( & ha - > pdev - > dev , ha - > md_template_size ,
ha - > md_tmplt_hdr , ha - > md_tmplt_hdr_dma ) ;
ha - > md_tmplt_hdr = 0 ;
}
/* Release the template data buffer allocated */
if ( ha - > md_dump ) {
ql_log ( ql_log_info , vha , 0xb049 ,
" Free MiniDump memory: %p, size (%d KB) \n " ,
ha - > md_dump , ha - > md_dump_size / 1024 ) ;
vfree ( ha - > md_dump ) ;
ha - > md_dump_size = 0 ;
ha - > md_dump = 0 ;
}
}
void
qla82xx_md_prep ( scsi_qla_host_t * vha )
{
struct qla_hw_data * ha = vha - > hw ;
int rval ;
/* Get Minidump template size */
rval = qla82xx_md_get_template_size ( vha ) ;
if ( rval = = QLA_SUCCESS ) {
ql_log ( ql_log_info , vha , 0xb04a ,
" MiniDump Template size obtained (%d KB) \n " ,
ha - > md_template_size / 1024 ) ;
/* Get Minidump template */
rval = qla82xx_md_get_template ( vha ) ;
if ( rval = = QLA_SUCCESS ) {
ql_dbg ( ql_dbg_p3p , vha , 0xb04b ,
" MiniDump Template obtained \n " ) ;
/* Allocate memory for minidump */
rval = qla82xx_md_alloc ( vha ) ;
if ( rval = = QLA_SUCCESS )
ql_log ( ql_log_info , vha , 0xb04c ,
" MiniDump memory allocated (%d KB) \n " ,
ha - > md_dump_size / 1024 ) ;
else {
ql_log ( ql_log_info , vha , 0xb04d ,
" Free MiniDump template: %p, size: (%d KB) \n " ,
ha - > md_tmplt_hdr ,
ha - > md_template_size / 1024 ) ;
dma_free_coherent ( & ha - > pdev - > dev ,
ha - > md_template_size ,
ha - > md_tmplt_hdr , ha - > md_tmplt_hdr_dma ) ;
ha - > md_tmplt_hdr = 0 ;
}
}
}
}
2011-08-16 11:31:45 -07:00
int
qla82xx_beacon_on ( struct scsi_qla_host * vha )
{
int rval ;
struct qla_hw_data * ha = vha - > hw ;
qla82xx_idc_lock ( ha ) ;
rval = qla82xx_mbx_beacon_ctl ( vha , 1 ) ;
if ( rval ) {
ql_log ( ql_log_warn , vha , 0xb050 ,
" mbx set led config failed in %s \n " , __func__ ) ;
goto exit ;
}
ha - > beacon_blink_led = 1 ;
exit :
qla82xx_idc_unlock ( ha ) ;
return rval ;
}
int
qla82xx_beacon_off ( struct scsi_qla_host * vha )
{
int rval ;
struct qla_hw_data * ha = vha - > hw ;
qla82xx_idc_lock ( ha ) ;
rval = qla82xx_mbx_beacon_ctl ( vha , 0 ) ;
if ( rval ) {
ql_log ( ql_log_warn , vha , 0xb051 ,
" mbx set led config failed in %s \n " , __func__ ) ;
goto exit ;
}
ha - > beacon_blink_led = 0 ;
exit :
qla82xx_idc_unlock ( ha ) ;
return rval ;
}