2010-07-28 14:23:44 +04:00
/*
* QLogic iSCSI HBA Driver
2013-08-16 15:03:04 +04:00
* Copyright ( c ) 2003 - 2013 QLogic Corporation
2010-07-28 14:23:44 +04:00
*
* See LICENSE . qla4xxx for copyright and licensing details .
*/
# include <linux/delay.h>
2010-09-14 16:12:54 +04:00
# include <linux/io.h>
2010-07-28 14:23:44 +04:00
# include <linux/pci.h>
2012-05-18 12:41:44 +04:00
# include <linux/ratelimit.h>
2010-07-28 14:23:44 +04:00
# include "ql4_def.h"
# include "ql4_glbl.h"
2012-08-22 15:55:08 +04:00
# include "ql4_inline.h"
2010-07-28 14:23:44 +04:00
2012-02-07 06:45:33 +04:00
# include <asm-generic/io-64-nonatomic-lo-hi.h>
2014-02-25 07:06:59 +04:00
# define TIMEOUT_100_MS 100
2010-07-28 14:23:44 +04:00
# define MASK(n) DMA_BIT_MASK(n)
# 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))
/* CRB window related */
# define CRB_BLK(off) ((off >> 20) & 0x3f)
# define CRB_SUBBLK(off) ((off >> 16) & 0xf)
# define CRB_WINDOW_2M (0x130060)
2012-08-22 15:55:00 +04:00
# define CRB_HI(off) ((qla4_82xx_crb_hub_agt[CRB_BLK(off)] << 20) | \
2010-07-28 14:23:44 +04:00
( ( off ) & 0xf0000 ) )
# define QLA82XX_PCI_CAMQM_2M_END (0x04800800UL)
# define QLA82XX_PCI_CAMQM_2M_BASE (0x000ff800UL)
# define CRB_INDIRECT_2M (0x1e0000UL)
static inline void __iomem *
qla4_8xxx_pci_base_offsetfset ( struct scsi_qla_host * ha , unsigned long off )
{
if ( ( off < ha - > first_page_group_end ) & &
( off > = ha - > first_page_group_start ) )
return ( void __iomem * ) ( ha - > nx_pcibase + off ) ;
return NULL ;
}
# define MAX_CRB_XFORM 60
static unsigned long crb_addr_xform [ MAX_CRB_XFORM ] ;
static int qla4_8xxx_crb_table_initialized ;
# define qla4_8xxx_crb_addr_transform(name) \
( crb_addr_xform [ QLA82XX_HW_PX_MAP_CRB_ # # name ] = \
QLA82XX_HW_CRB_HUB_AGT_ADR_ # # name < < 20 )
static void
2012-08-22 15:54:59 +04:00
qla4_82xx_crb_addr_transform_setup ( void )
2010-07-28 14:23:44 +04:00
{
qla4_8xxx_crb_addr_transform ( XDMA ) ;
qla4_8xxx_crb_addr_transform ( TIMR ) ;
qla4_8xxx_crb_addr_transform ( SRE ) ;
qla4_8xxx_crb_addr_transform ( SQN3 ) ;
qla4_8xxx_crb_addr_transform ( SQN2 ) ;
qla4_8xxx_crb_addr_transform ( SQN1 ) ;
qla4_8xxx_crb_addr_transform ( SQN0 ) ;
qla4_8xxx_crb_addr_transform ( SQS3 ) ;
qla4_8xxx_crb_addr_transform ( SQS2 ) ;
qla4_8xxx_crb_addr_transform ( SQS1 ) ;
qla4_8xxx_crb_addr_transform ( SQS0 ) ;
qla4_8xxx_crb_addr_transform ( RPMX7 ) ;
qla4_8xxx_crb_addr_transform ( RPMX6 ) ;
qla4_8xxx_crb_addr_transform ( RPMX5 ) ;
qla4_8xxx_crb_addr_transform ( RPMX4 ) ;
qla4_8xxx_crb_addr_transform ( RPMX3 ) ;
qla4_8xxx_crb_addr_transform ( RPMX2 ) ;
qla4_8xxx_crb_addr_transform ( RPMX1 ) ;
qla4_8xxx_crb_addr_transform ( RPMX0 ) ;
qla4_8xxx_crb_addr_transform ( ROMUSB ) ;
qla4_8xxx_crb_addr_transform ( SN ) ;
qla4_8xxx_crb_addr_transform ( QMN ) ;
qla4_8xxx_crb_addr_transform ( QMS ) ;
qla4_8xxx_crb_addr_transform ( PGNI ) ;
qla4_8xxx_crb_addr_transform ( PGND ) ;
qla4_8xxx_crb_addr_transform ( PGN3 ) ;
qla4_8xxx_crb_addr_transform ( PGN2 ) ;
qla4_8xxx_crb_addr_transform ( PGN1 ) ;
qla4_8xxx_crb_addr_transform ( PGN0 ) ;
qla4_8xxx_crb_addr_transform ( PGSI ) ;
qla4_8xxx_crb_addr_transform ( PGSD ) ;
qla4_8xxx_crb_addr_transform ( PGS3 ) ;
qla4_8xxx_crb_addr_transform ( PGS2 ) ;
qla4_8xxx_crb_addr_transform ( PGS1 ) ;
qla4_8xxx_crb_addr_transform ( PGS0 ) ;
qla4_8xxx_crb_addr_transform ( PS ) ;
qla4_8xxx_crb_addr_transform ( PH ) ;
qla4_8xxx_crb_addr_transform ( NIU ) ;
qla4_8xxx_crb_addr_transform ( I2Q ) ;
qla4_8xxx_crb_addr_transform ( EG ) ;
qla4_8xxx_crb_addr_transform ( MN ) ;
qla4_8xxx_crb_addr_transform ( MS ) ;
qla4_8xxx_crb_addr_transform ( CAS2 ) ;
qla4_8xxx_crb_addr_transform ( CAS1 ) ;
qla4_8xxx_crb_addr_transform ( CAS0 ) ;
qla4_8xxx_crb_addr_transform ( CAM ) ;
qla4_8xxx_crb_addr_transform ( C2C1 ) ;
qla4_8xxx_crb_addr_transform ( C2C0 ) ;
qla4_8xxx_crb_addr_transform ( SMB ) ;
qla4_8xxx_crb_addr_transform ( OCM0 ) ;
qla4_8xxx_crb_addr_transform ( I2C0 ) ;
qla4_8xxx_crb_table_initialized = 1 ;
}
static struct crb_128M_2M_block_map crb_128M_2M_map [ 64 ] = {
{ { { 0 , 0 , 0 , 0 } } } , /* 0: PCI */
{ { { 1 , 0x0100000 , 0x0102000 , 0x120000 } , /* 1: PCIE */
{ 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 } } } , /* 2: MN */
{ { { 0 , 0 , 0 , 0 } } } , /* 3: */
{ { { 1 , 0x0400000 , 0x0401000 , 0x169000 } } } , /* 4: P2NR1 */
{ { { 1 , 0x0500000 , 0x0510000 , 0x140000 } } } , /* 5: SRE */
{ { { 1 , 0x0600000 , 0x0610000 , 0x1c0000 } } } , /* 6: NIU */
{ { { 1 , 0x0700000 , 0x0704000 , 0x1b8000 } } } , /* 7: QM */
{ { { 1 , 0x0800000 , 0x0802000 , 0x170000 } , /* 8: SQM0 */
{ 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 } , /* 9: SQM1*/
{ 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 } , /* 10: SQM2*/
{ 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 } , /* 11: SQM3*/
{ 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 } } } , /* 12: I2Q */
{ { { 1 , 0x0d00000 , 0x0d04000 , 0x1a4000 } } } , /* 13: TMR */
{ { { 1 , 0x0e00000 , 0x0e04000 , 0x1a0000 } } } , /* 14: ROMUSB */
{ { { 1 , 0x0f00000 , 0x0f01000 , 0x164000 } } } , /* 15: PEG4 */
{ { { 0 , 0x1000000 , 0x1004000 , 0x1a8000 } } } , /* 16: XDMA */
{ { { 1 , 0x1100000 , 0x1101000 , 0x160000 } } } , /* 17: PEG0 */
{ { { 1 , 0x1200000 , 0x1201000 , 0x161000 } } } , /* 18: PEG1 */
{ { { 1 , 0x1300000 , 0x1301000 , 0x162000 } } } , /* 19: PEG2 */
{ { { 1 , 0x1400000 , 0x1401000 , 0x163000 } } } , /* 20: PEG3 */
{ { { 1 , 0x1500000 , 0x1501000 , 0x165000 } } } , /* 21: P2ND */
{ { { 1 , 0x1600000 , 0x1601000 , 0x166000 } } } , /* 22: P2NI */
{ { { 0 , 0 , 0 , 0 } } } , /* 23: */
{ { { 0 , 0 , 0 , 0 } } } , /* 24: */
{ { { 0 , 0 , 0 , 0 } } } , /* 25: */
{ { { 0 , 0 , 0 , 0 } } } , /* 26: */
{ { { 0 , 0 , 0 , 0 } } } , /* 27: */
{ { { 0 , 0 , 0 , 0 } } } , /* 28: */
{ { { 1 , 0x1d00000 , 0x1d10000 , 0x190000 } } } , /* 29: MS */
{ { { 1 , 0x1e00000 , 0x1e01000 , 0x16a000 } } } , /* 30: P2NR2 */
{ { { 1 , 0x1f00000 , 0x1f10000 , 0x150000 } } } , /* 31: EPG */
{ { { 0 } } } , /* 32: PCI */
{ { { 1 , 0x2100000 , 0x2102000 , 0x120000 } , /* 33: PCIE */
{ 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 } } } , /* 34: CAM */
{ { { 0 } } } , /* 35: */
{ { { 0 } } } , /* 36: */
{ { { 0 } } } , /* 37: */
{ { { 0 } } } , /* 38: */
{ { { 0 } } } , /* 39: */
{ { { 1 , 0x2800000 , 0x2804000 , 0x1a4000 } } } , /* 40: TMR */
{ { { 1 , 0x2900000 , 0x2901000 , 0x16b000 } } } , /* 41: P2NR3 */
{ { { 1 , 0x2a00000 , 0x2a00400 , 0x1ac400 } } } , /* 42: RPMX1 */
{ { { 1 , 0x2b00000 , 0x2b00400 , 0x1ac800 } } } , /* 43: RPMX2 */
{ { { 1 , 0x2c00000 , 0x2c00400 , 0x1acc00 } } } , /* 44: RPMX3 */
{ { { 1 , 0x2d00000 , 0x2d00400 , 0x1ad000 } } } , /* 45: RPMX4 */
{ { { 1 , 0x2e00000 , 0x2e00400 , 0x1ad400 } } } , /* 46: RPMX5 */
{ { { 1 , 0x2f00000 , 0x2f00400 , 0x1ad800 } } } , /* 47: RPMX6 */
{ { { 1 , 0x3000000 , 0x3000400 , 0x1adc00 } } } , /* 48: RPMX7 */
{ { { 0 , 0x3100000 , 0x3104000 , 0x1a8000 } } } , /* 49: XDMA */
{ { { 1 , 0x3200000 , 0x3204000 , 0x1d4000 } } } , /* 50: I2Q */
{ { { 1 , 0x3300000 , 0x3304000 , 0x1a0000 } } } , /* 51: ROMUSB */
{ { { 0 } } } , /* 52: */
{ { { 1 , 0x3500000 , 0x3500400 , 0x1ac000 } } } , /* 53: RPMX0 */
{ { { 1 , 0x3600000 , 0x3600400 , 0x1ae000 } } } , /* 54: RPMX8 */
{ { { 1 , 0x3700000 , 0x3700400 , 0x1ae400 } } } , /* 55: RPMX9 */
{ { { 1 , 0x3800000 , 0x3804000 , 0x1d0000 } } } , /* 56: OCM0 */
{ { { 1 , 0x3900000 , 0x3904000 , 0x1b4000 } } } , /* 57: CRYPTO */
{ { { 1 , 0x3a00000 , 0x3a04000 , 0x1d8000 } } } , /* 58: SMB */
{ { { 0 } } } , /* 59: I2C0 */
{ { { 0 } } } , /* 60: I2C1 */
{ { { 1 , 0x3d00000 , 0x3d04000 , 0x1dc000 } } } , /* 61: LPC */
{ { { 1 , 0x3e00000 , 0x3e01000 , 0x167000 } } } , /* 62: P2NC */
{ { { 1 , 0x3f00000 , 0x3f01000 , 0x168000 } } } /* 63: P2NR0 */
} ;
/*
* top 12 bits of crb internal address ( hub , agent )
*/
2012-08-22 15:55:00 +04:00
static unsigned qla4_82xx_crb_hub_agt [ 64 ] = {
2010-07-28 14:23:44 +04:00
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 ,
} ;
/* Device states */
static char * qdev_state [ ] = {
" Unknown " ,
" Cold " ,
" Initializing " ,
" Ready " ,
" Need Reset " ,
" Need Quiescent " ,
" Failed " ,
" Quiescent " ,
} ;
/*
* 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
2012-08-22 15:54:59 +04:00
qla4_82xx_pci_set_crbwindow_2M ( struct scsi_qla_host * ha , ulong * off )
2010-07-28 14:23:44 +04:00
{
u32 win_read ;
ha - > crb_win = CRB_HI ( * off ) ;
writel ( ha - > crb_win ,
( void __iomem * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ) ;
/* Read back value to make sure write has gone through before trying
* to use it . */
win_read = readl ( ( void __iomem * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ) ;
if ( win_read ! = ha - > crb_win ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: Written crbwin (0x%x) != Read crbwin (0x%x), "
" off=0x%lx \n " , __func__ , ha - > crb_win , win_read , * off ) ) ;
}
* off = ( * off & MASK ( 16 ) ) + CRB_INDIRECT_2M + ha - > nx_pcibase ;
}
void
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( struct scsi_qla_host * ha , ulong off , u32 data )
2010-07-28 14:23:44 +04:00
{
unsigned long flags = 0 ;
int rv ;
2012-08-22 15:54:59 +04:00
rv = qla4_82xx_pci_get_crb_addr_2M ( ha , & off ) ;
2010-07-28 14:23:44 +04:00
BUG_ON ( rv = = - 1 ) ;
if ( rv = = 1 ) {
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_crb_win_lock ( ha ) ;
qla4_82xx_pci_set_crbwindow_2M ( ha , & off ) ;
2010-07-28 14:23:44 +04:00
}
writel ( data , ( void __iomem * ) off ) ;
if ( rv = = 1 ) {
2012-08-22 15:54:59 +04:00
qla4_82xx_crb_win_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
}
}
2012-08-22 15:55:04 +04:00
uint32_t qla4_82xx_rd_32 ( struct scsi_qla_host * ha , ulong off )
2010-07-28 14:23:44 +04:00
{
unsigned long flags = 0 ;
int rv ;
u32 data ;
2012-08-22 15:54:59 +04:00
rv = qla4_82xx_pci_get_crb_addr_2M ( ha , & off ) ;
2010-07-28 14:23:44 +04:00
BUG_ON ( rv = = - 1 ) ;
if ( rv = = 1 ) {
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_crb_win_lock ( ha ) ;
qla4_82xx_pci_set_crbwindow_2M ( ha , & off ) ;
2010-07-28 14:23:44 +04:00
}
data = readl ( ( void __iomem * ) off ) ;
if ( rv = = 1 ) {
2012-08-22 15:54:59 +04:00
qla4_82xx_crb_win_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
}
return data ;
}
2012-05-18 12:41:44 +04:00
/* Minidump related functions */
2012-08-22 15:55:04 +04:00
int qla4_82xx_md_rd_32 ( struct scsi_qla_host * ha , uint32_t off , uint32_t * data )
2012-05-18 12:41:44 +04:00
{
2012-08-22 15:55:04 +04:00
uint32_t win_read , off_value ;
int rval = QLA_SUCCESS ;
2012-05-18 12:41:44 +04:00
off_value = off & 0xFFFF0000 ;
writel ( off_value , ( void __iomem * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ) ;
2012-08-22 15:55:04 +04:00
/*
* Read back value to make sure write has gone through before trying
2012-05-18 12:41:44 +04:00
* to use it .
*/
win_read = readl ( ( void __iomem * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ) ;
if ( win_read ! = off_value ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: Written (0x%x) != Read (0x%x), off=0x%x \n " ,
2012-08-22 15:55:04 +04:00
__func__ , off_value , win_read , off ) ) ;
rval = QLA_ERROR ;
} else {
off_value = off & 0x0000FFFF ;
* data = readl ( ( void __iomem * ) ( off_value + CRB_INDIRECT_2M +
ha - > nx_pcibase ) ) ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 15:55:04 +04:00
return rval ;
}
2012-05-18 12:41:44 +04:00
2012-08-22 15:55:04 +04:00
int qla4_82xx_md_wr_32 ( struct scsi_qla_host * ha , uint32_t off , uint32_t data )
{
uint32_t win_read , off_value ;
int rval = QLA_SUCCESS ;
2012-05-18 12:41:44 +04:00
2012-08-22 15:55:04 +04:00
off_value = off & 0xFFFF0000 ;
writel ( off_value , ( void __iomem * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ) ;
2012-05-18 12:41:44 +04:00
2012-08-22 15:55:04 +04:00
/* Read back value to make sure write has gone through before trying
* to use it .
*/
win_read = readl ( ( void __iomem * ) ( CRB_WINDOW_2M + ha - > nx_pcibase ) ) ;
if ( win_read ! = off_value ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: Written (0x%x) != Read (0x%x), off=0x%x \n " ,
__func__ , off_value , win_read , off ) ) ;
rval = QLA_ERROR ;
} else {
off_value = off & 0x0000FFFF ;
2012-05-18 12:41:44 +04:00
writel ( data , ( void __iomem * ) ( off_value + CRB_INDIRECT_2M +
ha - > nx_pcibase ) ) ;
2012-08-22 15:55:04 +04:00
}
2012-05-18 12:41:44 +04:00
return rval ;
}
2010-07-28 14:23:44 +04:00
# define CRB_WIN_LOCK_TIMEOUT 100000000
2012-08-22 15:54:59 +04:00
int qla4_82xx_crb_win_lock ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
int i ;
int done = 0 , timeout = 0 ;
while ( ! done ) {
/* acquire semaphore3 from PCI HW block */
2012-08-22 15:54:59 +04:00
done = qla4_82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM7_LOCK ) ) ;
2010-07-28 14:23:44 +04:00
if ( done = = 1 )
break ;
if ( timeout > = CRB_WIN_LOCK_TIMEOUT )
return - 1 ;
timeout + + ;
/* Yield CPU */
if ( ! in_interrupt ( ) )
schedule ( ) ;
else {
for ( i = 0 ; i < 20 ; i + + )
cpu_relax ( ) ; /*This a nop instr on i386*/
}
}
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_WIN_LOCK_ID , ha - > func_num ) ;
2010-07-28 14:23:44 +04:00
return 0 ;
}
2012-08-22 15:54:59 +04:00
void qla4_82xx_crb_win_unlock ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
2012-08-22 15:54:59 +04:00
qla4_82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM7_UNLOCK ) ) ;
2010-07-28 14:23:44 +04:00
}
# define IDC_LOCK_TIMEOUT 100000000
/**
2012-08-22 15:54:59 +04:00
* qla4_82xx_idc_lock - hw_lock
2010-07-28 14:23:44 +04:00
* @ ha : pointer to adapter structure
*
* General purpose lock used to synchronize access to
* CRB_DEV_STATE , CRB_DEV_REF_COUNT , etc .
* */
2012-08-22 15:54:59 +04:00
int qla4_82xx_idc_lock ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
int i ;
int done = 0 , timeout = 0 ;
while ( ! done ) {
/* acquire semaphore5 from PCI HW block */
2012-08-22 15:54:59 +04:00
done = qla4_82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM5_LOCK ) ) ;
2010-07-28 14:23:44 +04:00
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 ( ) ; /*This a nop instr on i386*/
}
}
return 0 ;
}
2012-08-22 15:54:59 +04:00
void qla4_82xx_idc_unlock ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
2012-08-22 15:54:59 +04:00
qla4_82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM5_UNLOCK ) ) ;
2010-07-28 14:23:44 +04:00
}
int
2012-08-22 15:54:59 +04:00
qla4_82xx_pci_get_crb_addr_2M ( struct scsi_qla_host * ha , ulong * off )
2010-07-28 14:23:44 +04:00
{
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 ;
}
/*
* check memory access boundary .
* used by test agent . support ddr access only for now
*/
static unsigned long
2012-08-22 15:54:59 +04:00
qla4_82xx_pci_mem_bound_check ( struct scsi_qla_host * ha ,
2010-07-28 14:23:44 +04:00
unsigned long long addr , int size )
{
2012-08-22 17:14:24 +04:00
if ( ! QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_DDR_NET ,
QLA8XXX_ADDR_DDR_NET_MAX ) | |
! QLA8XXX_ADDR_IN_RANGE ( addr + size - 1 ,
QLA8XXX_ADDR_DDR_NET , QLA8XXX_ADDR_DDR_NET_MAX ) | |
2010-07-28 14:23:44 +04:00
( ( size ! = 1 ) & & ( size ! = 2 ) & & ( size ! = 4 ) & & ( size ! = 8 ) ) ) {
return 0 ;
}
return 1 ;
}
2012-08-22 15:55:00 +04:00
static int qla4_82xx_pci_set_window_warning_count ;
2010-07-28 14:23:44 +04:00
static unsigned long
2012-08-22 15:54:59 +04:00
qla4_82xx_pci_set_window ( struct scsi_qla_host * ha , unsigned long long addr )
2010-07-28 14:23:44 +04:00
{
int window ;
u32 win_read ;
2012-08-22 17:14:24 +04:00
if ( QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_DDR_NET ,
QLA8XXX_ADDR_DDR_NET_MAX ) ) {
2010-07-28 14:23:44 +04:00
/* DDR network side */
window = MN_WIN ( addr ) ;
ha - > ddr_mn_window = window ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , ha - > mn_win_crb |
2010-07-28 14:23:44 +04:00
QLA82XX_PCI_CRBSPACE , window ) ;
2012-08-22 15:54:59 +04:00
win_read = qla4_82xx_rd_32 ( ha , ha - > mn_win_crb |
2010-07-28 14:23:44 +04:00
QLA82XX_PCI_CRBSPACE ) ;
if ( ( win_read < < 17 ) ! = window ) {
ql4_printk ( KERN_WARNING , ha ,
" %s: Written MNwin (0x%x) != Read MNwin (0x%x) \n " ,
__func__ , window , win_read ) ;
}
addr = GET_MEM_OFFS_2M ( addr ) + QLA82XX_PCI_DDR_NET ;
2012-08-22 17:14:24 +04:00
} else if ( QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_OCM0 ,
QLA8XXX_ADDR_OCM0_MAX ) ) {
2010-07-28 14:23:44 +04:00
unsigned int temp1 ;
/* if bits 19:18&17:11 are on */
if ( ( addr & 0x00ff800 ) = = 0xff800 ) {
printk ( " %s: QM access not handled. \n " , __func__ ) ;
addr = - 1UL ;
}
window = OCM_WIN ( addr ) ;
ha - > ddr_mn_window = window ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , ha - > mn_win_crb |
2010-07-28 14:23:44 +04:00
QLA82XX_PCI_CRBSPACE , window ) ;
2012-08-22 15:54:59 +04:00
win_read = qla4_82xx_rd_32 ( ha , ha - > mn_win_crb |
2010-07-28 14:23:44 +04:00
QLA82XX_PCI_CRBSPACE ) ;
temp1 = ( ( window & 0x1FF ) < < 7 ) |
( ( window & 0x0FFFE0000 ) > > 17 ) ;
if ( win_read ! = temp1 ) {
printk ( " %s: Written OCMwin (0x%x) != Read "
" OCMwin (0x%x) \n " , __func__ , temp1 , win_read ) ;
}
addr = GET_MEM_OFFS_2M ( addr ) + QLA82XX_PCI_OCM0_2M ;
2012-08-22 17:14:24 +04:00
} else if ( QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_QDR_NET ,
2010-07-28 14:23:44 +04:00
QLA82XX_P3_ADDR_QDR_NET_MAX ) ) {
/* QDR network side */
window = MS_WIN ( addr ) ;
ha - > qdr_sn_window = window ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , ha - > ms_win_crb |
2010-07-28 14:23:44 +04:00
QLA82XX_PCI_CRBSPACE , window ) ;
2012-08-22 15:54:59 +04:00
win_read = qla4_82xx_rd_32 ( ha ,
2010-07-28 14:23:44 +04:00
ha - > ms_win_crb | QLA82XX_PCI_CRBSPACE ) ;
if ( win_read ! = window ) {
printk ( " %s: Written MSwin (0x%x) != Read "
" MSwin (0x%x) \n " , __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 .
*/
2012-08-22 15:55:00 +04:00
if ( ( qla4_82xx_pci_set_window_warning_count + + < 8 ) | |
( qla4_82xx_pci_set_window_warning_count % 64 = = 0 ) ) {
2010-07-28 14:23:44 +04:00
printk ( " %s: Warning:%s Unknown address range! \n " ,
__func__ , DRIVER_NAME ) ;
}
addr = - 1UL ;
}
return addr ;
}
/* check if address is in the same windows as the previous access */
2012-08-22 15:54:59 +04:00
static int qla4_82xx_pci_is_same_window ( struct scsi_qla_host * ha ,
2010-07-28 14:23:44 +04:00
unsigned long long addr )
{
int window ;
unsigned long long qdr_max ;
qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX ;
2012-08-22 17:14:24 +04:00
if ( QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_DDR_NET ,
QLA8XXX_ADDR_DDR_NET_MAX ) ) {
2010-07-28 14:23:44 +04:00
/* DDR network side */
BUG ( ) ; /* MN access can not come here */
2012-08-22 17:14:24 +04:00
} else if ( QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_OCM0 ,
QLA8XXX_ADDR_OCM0_MAX ) ) {
2010-07-28 14:23:44 +04:00
return 1 ;
2012-08-22 17:14:24 +04:00
} else if ( QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_OCM1 ,
QLA8XXX_ADDR_OCM1_MAX ) ) {
2010-07-28 14:23:44 +04:00
return 1 ;
2012-08-22 17:14:24 +04:00
} else if ( QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_QDR_NET ,
2010-07-28 14:23:44 +04:00
qdr_max ) ) {
/* QDR network side */
2012-08-22 17:14:24 +04:00
window = ( ( addr - QLA8XXX_ADDR_QDR_NET ) > > 22 ) & 0x3f ;
2010-07-28 14:23:44 +04:00
if ( ha - > qdr_sn_window = = window )
return 1 ;
}
return 0 ;
}
2012-08-22 15:54:59 +04:00
static int qla4_82xx_pci_mem_read_direct ( struct scsi_qla_host * ha ,
2010-07-28 14:23:44 +04:00
u64 off , void * data , int size )
{
unsigned long flags ;
void __iomem * addr ;
int ret = 0 ;
u64 start ;
void __iomem * mem_ptr = NULL ;
unsigned long mem_base ;
unsigned long mem_page ;
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
/*
* If attempting to access unknown address or straddle hw windows ,
* do not access .
*/
2012-08-22 15:54:59 +04:00
start = qla4_82xx_pci_set_window ( ha , off ) ;
2010-07-28 14:23:44 +04:00
if ( ( start = = - 1UL ) | |
2012-08-22 15:54:59 +04:00
( qla4_82xx_pci_is_same_window ( ha , off + size - 1 ) = = 0 ) ) {
2010-07-28 14:23:44 +04:00
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
printk ( KERN_ERR " %s out of bound pci memory access. "
" offset is 0x%llx \n " , DRIVER_NAME , off ) ;
return - 1 ;
}
addr = qla4_8xxx_pci_base_offsetfset ( ha , start ) ;
if ( ! addr ) {
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 = = NULL ) {
* ( u8 * ) data = 0 ;
return - 1 ;
}
addr = mem_ptr ;
addr + = start & ( PAGE_SIZE - 1 ) ;
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
}
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
2012-08-22 15:54:59 +04:00
qla4_82xx_pci_mem_write_direct ( struct scsi_qla_host * ha , u64 off ,
2010-07-28 14:23:44 +04:00
void * data , int size )
{
unsigned long flags ;
void __iomem * addr ;
int ret = 0 ;
u64 start ;
void __iomem * mem_ptr = NULL ;
unsigned long mem_base ;
unsigned long mem_page ;
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
/*
* If attempting to access unknown address or straddle hw windows ,
* do not access .
*/
2012-08-22 15:54:59 +04:00
start = qla4_82xx_pci_set_window ( ha , off ) ;
2010-07-28 14:23:44 +04:00
if ( ( start = = - 1UL ) | |
2012-08-22 15:54:59 +04:00
( qla4_82xx_pci_is_same_window ( ha , off + size - 1 ) = = 0 ) ) {
2010-07-28 14:23:44 +04:00
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
printk ( KERN_ERR " %s out of bound pci memory access. "
" offset is 0x%llx \n " , DRIVER_NAME , off ) ;
return - 1 ;
}
addr = qla4_8xxx_pci_base_offsetfset ( ha , start ) ;
if ( ! addr ) {
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 = = NULL )
return - 1 ;
addr = mem_ptr ;
addr + = start & ( PAGE_SIZE - 1 ) ;
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
}
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
static unsigned long
2012-08-22 15:54:59 +04:00
qla4_82xx_decode_crb_addr ( unsigned long addr )
2010-07-28 14:23:44 +04:00
{
int i ;
unsigned long base_addr , offset , pci_base ;
if ( ! qla4_8xxx_crb_table_initialized )
2012-08-22 15:54:59 +04:00
qla4_82xx_crb_addr_transform_setup ( ) ;
2010-07-28 14:23:44 +04:00
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 ;
else
return pci_base + offset ;
}
static long rom_max_timeout = 100 ;
2012-08-22 15:55:00 +04:00
static long qla4_82xx_rom_lock_timeout = 100 ;
2010-07-28 14:23:44 +04:00
static int
2012-08-22 15:54:59 +04:00
qla4_82xx_rom_lock ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
int i ;
int done = 0 , timeout = 0 ;
while ( ! done ) {
/* acquire semaphore2 from PCI HW block */
2012-08-22 15:54:59 +04:00
done = qla4_82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM2_LOCK ) ) ;
2010-07-28 14:23:44 +04:00
if ( done = = 1 )
break ;
2012-08-22 15:55:00 +04:00
if ( timeout > = qla4_82xx_rom_lock_timeout )
2010-07-28 14:23:44 +04:00
return - 1 ;
timeout + + ;
/* Yield CPU */
if ( ! in_interrupt ( ) )
schedule ( ) ;
else {
for ( i = 0 ; i < 20 ; i + + )
cpu_relax ( ) ; /*This a nop instr on i386*/
}
}
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_ROM_LOCK_ID , ROM_LOCK_DRIVER ) ;
2010-07-28 14:23:44 +04:00
return 0 ;
}
static void
2012-08-22 15:54:59 +04:00
qla4_82xx_rom_unlock ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
2012-08-22 15:54:59 +04:00
qla4_82xx_rd_32 ( ha , QLA82XX_PCIE_REG ( PCIE_SEM2_UNLOCK ) ) ;
2010-07-28 14:23:44 +04:00
}
static int
2012-08-22 15:54:59 +04:00
qla4_82xx_wait_rom_done ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
long timeout = 0 ;
long done = 0 ;
while ( done = = 0 ) {
2012-08-22 15:54:59 +04:00
done = qla4_82xx_rd_32 ( ha , QLA82XX_ROMUSB_GLB_STATUS ) ;
2010-07-28 14:23:44 +04:00
done & = 2 ;
timeout + + ;
if ( timeout > = rom_max_timeout ) {
printk ( " %s: Timeout reached waiting for rom done " ,
DRIVER_NAME ) ;
return - 1 ;
}
}
return 0 ;
}
static int
2012-08-22 15:54:59 +04:00
qla4_82xx_do_rom_fast_read ( struct scsi_qla_host * ha , int addr , int * valp )
2010-07-28 14:23:44 +04:00
{
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_ADDRESS , addr ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_ABYTE_CNT , 3 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_INSTR_OPCODE , 0xb ) ;
if ( qla4_82xx_wait_rom_done ( ha ) ) {
2010-07-28 14:23:44 +04:00
printk ( " %s: Error waiting for rom done \n " , DRIVER_NAME ) ;
return - 1 ;
}
/* reset abyte_cnt and dummy_byte_cnt */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT , 0 ) ;
2010-07-28 14:23:44 +04:00
udelay ( 10 ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_ROM_ABYTE_CNT , 0 ) ;
2010-07-28 14:23:44 +04:00
2012-08-22 15:54:59 +04:00
* valp = qla4_82xx_rd_32 ( ha , QLA82XX_ROMUSB_ROM_RDATA ) ;
2010-07-28 14:23:44 +04:00
return 0 ;
}
static int
2012-08-22 15:54:59 +04:00
qla4_82xx_rom_fast_read ( struct scsi_qla_host * ha , int addr , int * valp )
2010-07-28 14:23:44 +04:00
{
int ret , loops = 0 ;
2012-08-22 15:54:59 +04:00
while ( ( qla4_82xx_rom_lock ( ha ) ! = 0 ) & & ( loops < 50000 ) ) {
2010-07-28 14:23:44 +04:00
udelay ( 100 ) ;
loops + + ;
}
if ( loops > = 50000 ) {
2012-08-22 15:54:59 +04:00
ql4_printk ( KERN_WARNING , ha , " %s: qla4_82xx_rom_lock failed \n " ,
DRIVER_NAME ) ;
2010-07-28 14:23:44 +04:00
return - 1 ;
}
2012-08-22 15:54:59 +04:00
ret = qla4_82xx_do_rom_fast_read ( ha , addr , valp ) ;
qla4_82xx_rom_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
return ret ;
}
/**
* This routine does CRB initialize sequence
* to put the ISP into operational state
* */
static int
2012-08-22 15:54:59 +04:00
qla4_82xx_pinit_from_rom ( struct scsi_qla_host * ha , int verbose )
2010-07-28 14:23:44 +04:00
{
int addr , val ;
int i ;
struct crb_addr_pair * buf ;
unsigned long off ;
unsigned offset , n ;
struct crb_addr_pair {
long addr ;
long data ;
} ;
/* Halt all the indiviual PEGs and other blocks of the ISP */
2012-08-22 15:54:59 +04:00
qla4_82xx_rom_lock ( ha ) ;
2010-12-03 09:12:15 +03:00
2011-05-18 10:17:04 +04:00
/* disable all I2Q */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x10 , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x14 , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x18 , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x1c , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x20 , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_I2Q + 0x24 , 0x0 ) ;
2011-05-18 10:17:04 +04:00
/* disable all niu interrupts */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0x40 , 0xff ) ;
2010-12-03 09:12:15 +03:00
/* disable xge rx/tx */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0x70000 , 0x00 ) ;
2010-12-03 09:12:15 +03:00
/* disable xg1 rx/tx */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0x80000 , 0x00 ) ;
2011-05-18 10:17:04 +04:00
/* disable sideband mac */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0x90000 , 0x00 ) ;
2011-05-18 10:17:04 +04:00
/* disable ap0 mac */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0xa0000 , 0x00 ) ;
2011-05-18 10:17:04 +04:00
/* disable ap1 mac */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_NIU + 0xb0000 , 0x00 ) ;
2010-12-03 09:12:15 +03:00
/* halt sre */
2012-08-22 15:54:59 +04:00
val = qla4_82xx_rd_32 ( ha , QLA82XX_CRB_SRE + 0x1000 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_SRE + 0x1000 , val & ( ~ ( 0x1 ) ) ) ;
2010-12-03 09:12:15 +03:00
/* halt epg */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_EPG + 0x1300 , 0x1 ) ;
2010-12-03 09:12:15 +03:00
/* halt timers */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x0 , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x8 , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x10 , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x18 , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x100 , 0x0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_TIMER + 0x200 , 0x0 ) ;
2010-12-03 09:12:15 +03:00
/* halt pegs */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_0 + 0x3c , 1 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_1 + 0x3c , 1 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_2 + 0x3c , 1 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_3 + 0x3c , 1 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_4 + 0x3c , 1 ) ;
2011-05-18 10:17:04 +04:00
msleep ( 5 ) ;
2010-12-03 09:12:15 +03:00
/* big hammer */
2010-07-28 14:23:44 +04:00
if ( test_bit ( DPC_RESET_HA , & ha - > dpc_flags ) )
/* don't reset CAM block on reset */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET , 0xfeffffff ) ;
2010-07-28 14:23:44 +04:00
else
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET , 0xffffffff ) ;
2010-07-28 14:23:44 +04:00
2012-08-22 15:54:59 +04:00
qla4_82xx_rom_unlock ( ha ) ;
2010-07-28 14:23:44 +04: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
*/
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_rom_fast_read ( ha , 0 , & n ) ! = 0 | | n ! = 0xcafecafeUL | |
qla4_82xx_rom_fast_read ( ha , 4 , & n ) ! = 0 ) {
2010-07-28 14:23:44 +04:00
ql4_printk ( KERN_WARNING , ha ,
" [ERROR] Reading crb_init area: n: %08x \n " , n ) ;
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 ) {
ql4_printk ( KERN_WARNING , ha ,
" %s: %s:n=0x%x [ERROR] Card flash not initialized. \n " ,
DRIVER_NAME , __func__ , n ) ;
return - 1 ;
}
ql4_printk ( KERN_INFO , ha ,
" %s: %d CRB init values found in ROM. \n " , DRIVER_NAME , n ) ;
buf = kmalloc ( n * sizeof ( struct crb_addr_pair ) , GFP_KERNEL ) ;
if ( buf = = NULL ) {
ql4_printk ( KERN_WARNING , ha ,
" %s: [ERROR] Unable to malloc memory. \n " , DRIVER_NAME ) ;
return - 1 ;
}
for ( i = 0 ; i < n ; i + + ) {
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_rom_fast_read ( ha , 8 * i + 4 * offset , & val ) ! = 0 | |
qla4_82xx_rom_fast_read ( ha , 8 * i + 4 * offset + 4 , & addr ) ! =
2010-07-28 14:23:44 +04:00
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
*/
2012-08-22 15:54:59 +04:00
off = qla4_82xx_decode_crb_addr ( ( unsigned long ) buf [ i ] . addr ) +
2010-07-28 14:23:44 +04:00
QLA82XX_PCI_CRBSPACE ;
/* Not all CRB addr/value pair to be written,
* some of them are skipped
*/
/* skip if LS bit is set*/
if ( off & 0x1 ) {
DEBUG2 ( ql4_printk ( KERN_WARNING , ha ,
" Skip CRB init replay for offset = 0x%lx \n " , off ) ) ;
continue ;
}
/* 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 ) {
ql4_printk ( KERN_WARNING , ha ,
" %s: [ERROR] Unknown addr: 0x%08lx \n " ,
DRIVER_NAME , buf [ i ] . addr ) ;
continue ;
}
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , off , buf [ i ] . data ) ;
2010-07-28 14:23:44 +04:00
/* 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 */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_D + 0xec , 0x1e ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_D + 0x4c , 8 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_I + 0x4c , 8 ) ;
2010-07-28 14:23:44 +04:00
/* Clear all protocol processing engines */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_0 + 0x8 , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_0 + 0xc , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_1 + 0x8 , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_1 + 0xc , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_2 + 0x8 , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_2 + 0xc , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_3 + 0x8 , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_3 + 0xc , 0 ) ;
2010-07-28 14:23:44 +04:00
return 0 ;
}
2014-02-25 07:07:01 +04:00
/**
* qla4_8xxx_ms_mem_write_128b - Writes data to MS / off - chip memory
* @ ha : Pointer to adapter structure
* @ addr : Flash address to write to
* @ data : Data to be written
* @ count : word_count to be written
*
* Return : On success return QLA_SUCCESS
* On error return QLA_ERROR
* */
int qla4_8xxx_ms_mem_write_128b ( struct scsi_qla_host * ha , uint64_t addr ,
uint32_t * data , uint32_t count )
{
int i , j ;
uint32_t agt_ctrl ;
unsigned long flags ;
int ret_val = QLA_SUCCESS ;
/* Only 128-bit aligned access */
if ( addr & 0xF ) {
ret_val = QLA_ERROR ;
goto exit_ms_mem_write ;
}
write_lock_irqsave ( & ha - > hw_lock , flags ) ;
/* Write address */
ret_val = ha - > isp_ops - > wr_reg_indirect ( ha , MD_MIU_TEST_AGT_ADDR_HI , 0 ) ;
if ( ret_val = = QLA_ERROR ) {
ql4_printk ( KERN_ERR , ha , " %s: write to AGT_ADDR_HI failed \n " ,
__func__ ) ;
goto exit_ms_mem_write_unlock ;
}
for ( i = 0 ; i < count ; i + + , addr + = 16 ) {
if ( ! ( ( QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_QDR_NET ,
QLA8XXX_ADDR_QDR_NET_MAX ) ) | |
( QLA8XXX_ADDR_IN_RANGE ( addr , QLA8XXX_ADDR_DDR_NET ,
QLA8XXX_ADDR_DDR_NET_MAX ) ) ) ) {
ret_val = QLA_ERROR ;
goto exit_ms_mem_write_unlock ;
}
ret_val = ha - > isp_ops - > wr_reg_indirect ( ha ,
MD_MIU_TEST_AGT_ADDR_LO ,
addr ) ;
/* Write data */
ret_val | = ha - > isp_ops - > wr_reg_indirect ( ha ,
MD_MIU_TEST_AGT_WRDATA_LO ,
* data + + ) ;
ret_val | = ha - > isp_ops - > wr_reg_indirect ( ha ,
MD_MIU_TEST_AGT_WRDATA_HI ,
* data + + ) ;
ret_val | = ha - > isp_ops - > wr_reg_indirect ( ha ,
MD_MIU_TEST_AGT_WRDATA_ULO ,
* data + + ) ;
ret_val | = ha - > isp_ops - > wr_reg_indirect ( ha ,
MD_MIU_TEST_AGT_WRDATA_UHI ,
* data + + ) ;
if ( ret_val = = QLA_ERROR ) {
ql4_printk ( KERN_ERR , ha , " %s: write to AGT_WRDATA failed \n " ,
__func__ ) ;
goto exit_ms_mem_write_unlock ;
}
/* Check write status */
ret_val = ha - > isp_ops - > wr_reg_indirect ( ha , MD_MIU_TEST_AGT_CTRL ,
MIU_TA_CTL_WRITE_ENABLE ) ;
ret_val | = ha - > isp_ops - > wr_reg_indirect ( ha ,
MD_MIU_TEST_AGT_CTRL ,
MIU_TA_CTL_WRITE_START ) ;
if ( ret_val = = QLA_ERROR ) {
ql4_printk ( KERN_ERR , ha , " %s: write to AGT_CTRL failed \n " ,
__func__ ) ;
goto exit_ms_mem_write_unlock ;
}
for ( j = 0 ; j < MAX_CTL_CHECK ; j + + ) {
ret_val = ha - > isp_ops - > rd_reg_indirect ( ha ,
MD_MIU_TEST_AGT_CTRL ,
& agt_ctrl ) ;
if ( ret_val = = QLA_ERROR ) {
ql4_printk ( KERN_ERR , ha , " %s: failed to read MD_MIU_TEST_AGT_CTRL \n " ,
__func__ ) ;
goto exit_ms_mem_write_unlock ;
}
if ( ( agt_ctrl & MIU_TA_CTL_BUSY ) = = 0 )
break ;
}
/* Status check failed */
if ( j > = MAX_CTL_CHECK ) {
printk_ratelimited ( KERN_ERR " %s: MS memory write failed! \n " ,
__func__ ) ;
ret_val = QLA_ERROR ;
goto exit_ms_mem_write_unlock ;
}
}
exit_ms_mem_write_unlock :
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
exit_ms_mem_write :
return ret_val ;
}
2010-07-28 14:23:44 +04:00
static int
2012-08-22 15:54:59 +04:00
qla4_82xx_load_from_flash ( struct scsi_qla_host * ha , uint32_t image_start )
2010-07-28 14:23:44 +04:00
{
2010-12-03 09:12:40 +03:00
int i , rval = 0 ;
2010-07-28 14:23:44 +04:00
long size = 0 ;
long flashaddr , memaddr ;
u64 data ;
u32 high , low ;
flashaddr = memaddr = ha - > hw . flt_region_bootload ;
2010-12-03 09:12:40 +03:00
size = ( image_start - flashaddr ) / 8 ;
2010-07-28 14:23:44 +04:00
DEBUG2 ( printk ( " scsi%ld: %s: bootldr=0x%lx, fw_image=0x%x \n " ,
ha - > host_no , __func__ , flashaddr , image_start ) ) ;
for ( i = 0 ; i < size ; i + + ) {
2012-08-22 15:54:59 +04:00
if ( ( qla4_82xx_rom_fast_read ( ha , flashaddr , ( int * ) & low ) ) | |
( qla4_82xx_rom_fast_read ( ha , flashaddr + 4 ,
2010-07-28 14:23:44 +04:00
( int * ) & high ) ) ) {
2010-12-03 09:12:40 +03:00
rval = - 1 ;
goto exit_load_from_flash ;
2010-07-28 14:23:44 +04:00
}
data = ( ( u64 ) high < < 32 ) | low ;
2012-08-22 15:54:59 +04:00
rval = qla4_82xx_pci_mem_write_2M ( ha , memaddr , & data , 8 ) ;
2010-12-03 09:12:40 +03:00
if ( rval )
goto exit_load_from_flash ;
2010-07-28 14:23:44 +04:00
flashaddr + = 8 ;
memaddr + = 8 ;
2010-12-03 09:12:40 +03:00
if ( i % 0x1000 = = 0 )
2010-07-28 14:23:44 +04:00
msleep ( 1 ) ;
}
udelay ( 100 ) ;
read_lock ( & ha - > hw_lock ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_PEG_NET_0 + 0x18 , 0x1020 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET , 0x80001e ) ;
2010-07-28 14:23:44 +04:00
read_unlock ( & ha - > hw_lock ) ;
2010-12-03 09:12:40 +03:00
exit_load_from_flash :
return rval ;
2010-07-28 14:23:44 +04:00
}
2012-08-22 15:54:59 +04:00
static int qla4_82xx_load_fw ( struct scsi_qla_host * ha , uint32_t image_start )
2010-07-28 14:23:44 +04:00
{
u32 rst ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , CRB_CMDPEG_STATE , 0 ) ;
if ( qla4_82xx_pinit_from_rom ( ha , 0 ) ! = QLA_SUCCESS ) {
2010-07-28 14:23:44 +04:00
printk ( KERN_WARNING " %s: Error during CRB Initialization \n " ,
__func__ ) ;
return QLA_ERROR ;
}
udelay ( 500 ) ;
/* at this point, QM is in reset. This could be a problem if there are
* incoming d * transition queue messages . QM / PCIE could wedge .
* To get around this , QM is brought out of reset .
*/
2012-08-22 15:54:59 +04:00
rst = qla4_82xx_rd_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET ) ;
2010-07-28 14:23:44 +04:00
/* unreset qm */
rst & = ~ ( 1 < < 28 ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_ROMUSB_GLB_SW_RESET , rst ) ;
2010-07-28 14:23:44 +04:00
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_load_from_flash ( ha , image_start ) ) {
2010-07-28 14:23:44 +04:00
printk ( " %s: Error trying to load fw from flash! \n " , __func__ ) ;
return QLA_ERROR ;
}
return QLA_SUCCESS ;
}
int
2012-08-22 15:54:59 +04:00
qla4_82xx_pci_mem_read_2M ( struct scsi_qla_host * ha ,
2010-07-28 14:23:44 +04:00
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 .
*/
2012-08-22 17:14:24 +04:00
if ( off > = QLA8XXX_ADDR_QDR_NET & & off < = QLA82XX_P3_ADDR_QDR_NET_MAX )
2010-07-28 14:23:44 +04:00
mem_crb = QLA82XX_CRB_QDR_NET ;
else {
mem_crb = QLA82XX_CRB_DDR_NET ;
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_pci_mem_bound_check ( ha , off , size ) = = 0 )
return qla4_82xx_pci_mem_read_direct ( ha ,
2010-07-28 14:23:44 +04:00
off , data , size ) ;
}
off8 = off & 0xfffffff0 ;
off0 [ 0 ] = off & 0xf ;
sz [ 0 ] = ( size < ( 16 - off0 [ 0 ] ) ) ? size : ( 16 - off0 [ 0 ] ) ;
shift_amount = 4 ;
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 ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_ADDR_LO , temp ) ;
2010-07-28 14:23:44 +04:00
temp = 0 ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_ADDR_HI , temp ) ;
2010-07-28 14:23:44 +04:00
temp = MIU_TA_CTL_ENABLE ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL , temp ) ;
2012-08-22 15:55:03 +04:00
temp = MIU_TA_CTL_START_ENABLE ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL , temp ) ;
2010-07-28 14:23:44 +04:00
for ( j = 0 ; j < MAX_CTL_CHECK ; j + + ) {
2012-08-22 15:54:59 +04:00
temp = qla4_82xx_rd_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL ) ;
2010-07-28 14:23:44 +04:00
if ( ( temp & MIU_TA_CTL_BUSY ) = = 0 )
break ;
}
if ( j > = MAX_CTL_CHECK ) {
2012-05-18 12:41:44 +04:00
printk_ratelimited ( KERN_ERR
" %s: failed to read through agent \n " ,
__func__ ) ;
2010-07-28 14:23:44 +04:00
break ;
}
start = off0 [ i ] > > 2 ;
end = ( off0 [ i ] + sz [ i ] - 1 ) > > 2 ;
for ( k = start ; k < = end ; k + + ) {
2012-08-22 15:54:59 +04:00
temp = qla4_82xx_rd_32 ( ha ,
2010-07-28 14:23:44 +04:00
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 ;
}
int
2012-08-22 15:54:59 +04:00
qla4_82xx_pci_mem_write_2M ( struct scsi_qla_host * ha ,
2010-07-28 14:23:44 +04:00
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 .
*/
2012-08-22 17:14:24 +04:00
if ( off > = QLA8XXX_ADDR_QDR_NET & & off < = QLA82XX_P3_ADDR_QDR_NET_MAX )
2010-07-28 14:23:44 +04:00
mem_crb = QLA82XX_CRB_QDR_NET ;
else {
mem_crb = QLA82XX_CRB_DDR_NET ;
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_pci_mem_bound_check ( ha , off , size ) = = 0 )
return qla4_82xx_pci_mem_write_direct ( ha ,
2010-07-28 14:23:44 +04:00
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 + + ) {
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_pci_mem_read_2M ( ha , off8 +
2010-07-28 14:23:44 +04:00
( 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 ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_ADDR_LO , temp ) ;
2010-07-28 14:23:44 +04:00
temp = 0 ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_ADDR_HI , temp ) ;
2010-07-28 14:23:44 +04:00
temp = word [ i * scale ] & 0xffffffff ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_WRDATA_LO , temp ) ;
2010-07-28 14:23:44 +04:00
temp = ( word [ i * scale ] > > 32 ) & 0xffffffff ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_WRDATA_HI , temp ) ;
2010-07-28 14:23:44 +04:00
temp = word [ i * scale + 1 ] & 0xffffffff ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_WRDATA_UPPER_LO ,
2010-07-28 14:23:44 +04:00
temp ) ;
temp = ( word [ i * scale + 1 ] > > 32 ) & 0xffffffff ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_WRDATA_UPPER_HI ,
2010-07-28 14:23:44 +04:00
temp ) ;
2012-08-22 15:55:03 +04:00
temp = MIU_TA_CTL_WRITE_ENABLE ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL , temp ) ;
2012-08-22 15:55:03 +04:00
temp = MIU_TA_CTL_WRITE_START ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL , temp ) ;
2010-07-28 14:23:44 +04:00
for ( j = 0 ; j < MAX_CTL_CHECK ; j + + ) {
2012-08-22 15:54:59 +04:00
temp = qla4_82xx_rd_32 ( ha , mem_crb + MIU_TEST_AGT_CTRL ) ;
2010-07-28 14:23:44 +04:00
if ( ( temp & MIU_TA_CTL_BUSY ) = = 0 )
break ;
}
if ( j > = MAX_CTL_CHECK ) {
if ( printk_ratelimit ( ) )
ql4_printk ( KERN_ERR , ha ,
2012-05-18 12:41:44 +04:00
" %s: failed to read through agent \n " ,
__func__ ) ;
2010-07-28 14:23:44 +04:00
ret = - 1 ;
break ;
}
}
return ret ;
}
2012-08-22 15:54:59 +04:00
static int qla4_82xx_cmdpeg_ready ( struct scsi_qla_host * ha , int pegtune_val )
2010-07-28 14:23:44 +04:00
{
u32 val = 0 ;
int retries = 60 ;
if ( ! pegtune_val ) {
do {
2012-08-22 15:54:59 +04:00
val = qla4_82xx_rd_32 ( ha , CRB_CMDPEG_STATE ) ;
2010-07-28 14:23:44 +04:00
if ( ( val = = PHAN_INITIALIZE_COMPLETE ) | |
( val = = PHAN_INITIALIZE_ACK ) )
return 0 ;
set_current_state ( TASK_UNINTERRUPTIBLE ) ;
schedule_timeout ( 500 ) ;
} while ( - - retries ) ;
if ( ! retries ) {
2012-08-22 15:54:59 +04:00
pegtune_val = qla4_82xx_rd_32 ( ha ,
2010-07-28 14:23:44 +04:00
QLA82XX_ROMUSB_GLB_PEGTUNE_DONE ) ;
printk ( KERN_WARNING " %s: init failed, "
" pegtune_val = %x \n " , __func__ , pegtune_val ) ;
return - 1 ;
}
}
return 0 ;
}
2012-08-22 15:54:59 +04:00
static int qla4_82xx_rcvpeg_ready ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
uint32_t state = 0 ;
int loops = 0 ;
/* Window 1 call */
read_lock ( & ha - > hw_lock ) ;
2012-08-22 15:54:59 +04:00
state = qla4_82xx_rd_32 ( ha , CRB_RCVPEG_STATE ) ;
2010-07-28 14:23:44 +04:00
read_unlock ( & ha - > hw_lock ) ;
while ( ( state ! = PHAN_PEG_RCV_INITIALIZED ) & & ( loops < 30000 ) ) {
udelay ( 100 ) ;
/* Window 1 call */
read_lock ( & ha - > hw_lock ) ;
2012-08-22 15:54:59 +04:00
state = qla4_82xx_rd_32 ( ha , CRB_RCVPEG_STATE ) ;
2010-07-28 14:23:44 +04:00
read_unlock ( & ha - > hw_lock ) ;
loops + + ;
}
if ( loops > = 30000 ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" Receive Peg initialization not complete: 0x%x. \n " , state ) ) ;
return QLA_ERROR ;
}
return QLA_SUCCESS ;
}
2010-08-20 01:13:42 +04:00
void
2010-07-28 14:23:44 +04:00
qla4_8xxx_set_drv_active ( struct scsi_qla_host * ha )
{
uint32_t drv_active ;
2012-08-22 15:55:04 +04:00
drv_active = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_ACTIVE ) ;
2012-08-22 15:55:08 +04:00
/*
2013-08-16 15:03:02 +04:00
* For ISP8324 and ISP8042 , drv_active register has 1 bit per function ,
2012-08-22 15:55:08 +04:00
* shift 1 by func_num to set a bit for the function .
* For ISP8022 , drv_active has 4 bits per function
*/
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) )
2012-08-22 15:55:08 +04:00
drv_active | = ( 1 < < ha - > func_num ) ;
else
drv_active | = ( 1 < < ( ha - > func_num * 4 ) ) ;
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha , " %s(%ld): drv_active: 0x%08x \n " ,
__func__ , ha - > host_no , drv_active ) ;
2012-08-22 15:55:04 +04:00
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DRV_ACTIVE , drv_active ) ;
2010-07-28 14:23:44 +04:00
}
void
qla4_8xxx_clear_drv_active ( struct scsi_qla_host * ha )
{
uint32_t drv_active ;
2012-08-22 15:55:04 +04:00
drv_active = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_ACTIVE ) ;
2012-08-22 15:55:08 +04:00
/*
2013-08-16 15:03:02 +04:00
* For ISP8324 and ISP8042 , drv_active register has 1 bit per function ,
2012-08-22 15:55:08 +04:00
* shift 1 by func_num to set a bit for the function .
* For ISP8022 , drv_active has 4 bits per function
*/
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) )
2012-08-22 15:55:08 +04:00
drv_active & = ~ ( 1 < < ( ha - > func_num ) ) ;
else
drv_active & = ~ ( 1 < < ( ha - > func_num * 4 ) ) ;
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha , " %s(%ld): drv_active: 0x%08x \n " ,
__func__ , ha - > host_no , drv_active ) ;
2012-08-22 15:55:04 +04:00
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DRV_ACTIVE , drv_active ) ;
2010-07-28 14:23:44 +04:00
}
2012-08-22 15:55:04 +04:00
inline int qla4_8xxx_need_reset ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
2010-07-30 13:08:47 +04:00
uint32_t drv_state , drv_active ;
2010-07-28 14:23:44 +04:00
int rval ;
2012-08-22 15:55:04 +04:00
drv_active = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_ACTIVE ) ;
drv_state = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_STATE ) ;
2012-08-22 15:55:08 +04:00
/*
2013-08-16 15:03:02 +04:00
* For ISP8324 and ISP8042 , drv_active register has 1 bit per function ,
2012-08-22 15:55:08 +04:00
* shift 1 by func_num to set a bit for the function .
* For ISP8022 , drv_active has 4 bits per function
*/
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) )
2012-08-22 15:55:08 +04:00
rval = drv_state & ( 1 < < ha - > func_num ) ;
else
rval = drv_state & ( 1 < < ( ha - > func_num * 4 ) ) ;
2010-07-30 13:08:47 +04:00
if ( ( test_bit ( AF_EEH_BUSY , & ha - > flags ) ) & & drv_active )
rval = 1 ;
2010-07-28 14:23:44 +04:00
return rval ;
}
2012-08-22 15:55:08 +04:00
void qla4_8xxx_set_rst_ready ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
uint32_t drv_state ;
2012-08-22 15:55:04 +04:00
drv_state = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_STATE ) ;
2012-08-22 15:55:08 +04:00
/*
2013-08-16 15:03:02 +04:00
* For ISP8324 and ISP8042 , drv_active register has 1 bit per function ,
2012-08-22 15:55:08 +04:00
* shift 1 by func_num to set a bit for the function .
* For ISP8022 , drv_active has 4 bits per function
*/
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) )
2012-08-22 15:55:08 +04:00
drv_state | = ( 1 < < ha - > func_num ) ;
else
drv_state | = ( 1 < < ( ha - > func_num * 4 ) ) ;
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha , " %s(%ld): drv_state: 0x%08x \n " ,
__func__ , ha - > host_no , drv_state ) ;
2012-08-22 15:55:04 +04:00
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DRV_STATE , drv_state ) ;
2010-07-28 14:23:44 +04:00
}
2012-08-22 15:55:08 +04:00
void qla4_8xxx_clear_rst_ready ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
uint32_t drv_state ;
2012-08-22 15:55:04 +04:00
drv_state = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_STATE ) ;
2012-08-22 15:55:08 +04:00
/*
2013-08-16 15:03:02 +04:00
* For ISP8324 and ISP8042 , drv_active register has 1 bit per function ,
2012-08-22 15:55:08 +04:00
* shift 1 by func_num to set a bit for the function .
* For ISP8022 , drv_active has 4 bits per function
*/
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) )
2012-08-22 15:55:08 +04:00
drv_state & = ~ ( 1 < < ha - > func_num ) ;
else
drv_state & = ~ ( 1 < < ( ha - > func_num * 4 ) ) ;
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha , " %s(%ld): drv_state: 0x%08x \n " ,
__func__ , ha - > host_no , drv_state ) ;
2012-08-22 15:55:04 +04:00
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DRV_STATE , drv_state ) ;
2010-07-28 14:23:44 +04:00
}
static inline void
qla4_8xxx_set_qsnt_ready ( struct scsi_qla_host * ha )
{
uint32_t qsnt_state ;
2012-08-22 15:55:04 +04:00
qsnt_state = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_STATE ) ;
2012-08-22 15:55:08 +04:00
/*
2013-08-16 15:03:02 +04:00
* For ISP8324 and ISP8042 , drv_active register has 1 bit per function ,
2012-08-22 15:55:08 +04:00
* shift 1 by func_num to set a bit for the function .
* For ISP8022 , drv_active has 4 bits per function .
*/
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) )
2012-08-22 15:55:08 +04:00
qsnt_state | = ( 1 < < ha - > func_num ) ;
else
qsnt_state | = ( 2 < < ( ha - > func_num * 4 ) ) ;
2012-08-22 15:55:04 +04:00
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DRV_STATE , qsnt_state ) ;
2010-07-28 14:23:44 +04:00
}
static int
2012-08-22 15:54:59 +04:00
qla4_82xx_start_firmware ( struct scsi_qla_host * ha , uint32_t image_start )
2010-07-28 14:23:44 +04:00
{
uint16_t lnk ;
/* scrub dma mask expansion register */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , CRB_DMA_SHIFT , 0x55555555 ) ;
2010-07-28 14:23:44 +04:00
/* Overwrite stale initialization register values */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , CRB_CMDPEG_STATE , 0 ) ;
qla4_82xx_wr_32 ( ha , CRB_RCVPEG_STATE , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_PEG_HALT_STATUS1 , 0 ) ;
qla4_82xx_wr_32 ( ha , QLA82XX_PEG_HALT_STATUS2 , 0 ) ;
2010-07-28 14:23:44 +04:00
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_load_fw ( ha , image_start ) ! = QLA_SUCCESS ) {
2010-07-28 14:23:44 +04:00
printk ( " %s: Error trying to start fw! \n " , __func__ ) ;
return QLA_ERROR ;
}
/* Handshake with the card before we register the devices. */
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_cmdpeg_ready ( ha , 0 ) ! = QLA_SUCCESS ) {
2010-07-28 14:23:44 +04:00
printk ( " %s: Error during card handshake! \n " , __func__ ) ;
return QLA_ERROR ;
}
/* Negotiated Link width */
2012-08-21 00:25:06 +04:00
pcie_capability_read_word ( ha - > pdev , PCI_EXP_LNKSTA , & lnk ) ;
2010-07-28 14:23:44 +04:00
ha - > link_width = ( lnk > > 4 ) & 0x3f ;
/* Synchronize with Receive peg */
2012-08-22 15:54:59 +04:00
return qla4_82xx_rcvpeg_ready ( ha ) ;
2010-07-28 14:23:44 +04:00
}
2012-08-22 15:55:04 +04:00
int qla4_82xx_try_start_fw ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
int rval = QLA_ERROR ;
/*
* FW Load priority :
* 1 ) Operational firmware residing in flash .
* 2 ) Fail
*/
ql4_printk ( KERN_INFO , ha ,
" FW: Retrieving flash offsets from FLT/FDT ... \n " ) ;
rval = qla4_8xxx_get_flash_info ( ha ) ;
if ( rval ! = QLA_SUCCESS )
return rval ;
ql4_printk ( KERN_INFO , ha ,
" FW: Attempting to load firmware from flash... \n " ) ;
2012-08-22 15:54:59 +04:00
rval = qla4_82xx_start_firmware ( ha , ha - > hw . flt_region_fw ) ;
2010-07-28 14:23:44 +04:00
2010-10-07 09:47:48 +04:00
if ( rval ! = QLA_SUCCESS ) {
ql4_printk ( KERN_ERR , ha , " FW: Load firmware from flash "
" FAILED... \n " ) ;
return rval ;
}
2010-07-28 14:23:44 +04:00
return rval ;
}
2012-08-22 15:55:04 +04:00
void qla4_82xx_rom_lock_recovery ( struct scsi_qla_host * ha )
2010-10-07 09:50:51 +04:00
{
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_rom_lock ( ha ) ) {
2010-10-07 09:50:51 +04:00
/* Someone else is holding the lock. */
dev_info ( & ha - > pdev - > dev , " Resetting rom_lock \n " ) ;
}
/*
* Either we got the lock , or someone
* else died while holding it .
* In either case , unlock .
*/
2012-08-22 15:54:59 +04:00
qla4_82xx_rom_unlock ( ha ) ;
2010-10-07 09:50:51 +04:00
}
2014-02-25 07:06:59 +04:00
static uint32_t ql4_84xx_poll_wait_for_ready ( struct scsi_qla_host * ha ,
uint32_t addr1 , uint32_t mask )
{
unsigned long timeout ;
uint32_t rval = QLA_SUCCESS ;
uint32_t temp ;
timeout = jiffies + msecs_to_jiffies ( TIMEOUT_100_MS ) ;
do {
ha - > isp_ops - > rd_reg_indirect ( ha , addr1 , & temp ) ;
if ( ( temp & mask ) ! = 0 )
break ;
if ( time_after_eq ( jiffies , timeout ) ) {
ql4_printk ( KERN_INFO , ha , " Error in processing rdmdio entry \n " ) ;
return QLA_ERROR ;
}
} while ( 1 ) ;
return rval ;
}
uint32_t ql4_84xx_ipmdio_rd_reg ( struct scsi_qla_host * ha , uint32_t addr1 ,
uint32_t addr3 , uint32_t mask , uint32_t addr ,
uint32_t * data_ptr )
{
int rval = QLA_SUCCESS ;
uint32_t temp ;
uint32_t data ;
rval = ql4_84xx_poll_wait_for_ready ( ha , addr1 , mask ) ;
if ( rval )
goto exit_ipmdio_rd_reg ;
temp = ( 0x40000000 | addr ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , addr1 , temp ) ;
rval = ql4_84xx_poll_wait_for_ready ( ha , addr1 , mask ) ;
if ( rval )
goto exit_ipmdio_rd_reg ;
ha - > isp_ops - > rd_reg_indirect ( ha , addr3 , & data ) ;
* data_ptr = data ;
exit_ipmdio_rd_reg :
return rval ;
}
static uint32_t ql4_84xx_poll_wait_ipmdio_bus_idle ( struct scsi_qla_host * ha ,
uint32_t addr1 ,
uint32_t addr2 ,
uint32_t addr3 ,
uint32_t mask )
{
unsigned long timeout ;
uint32_t temp ;
uint32_t rval = QLA_SUCCESS ;
timeout = jiffies + msecs_to_jiffies ( TIMEOUT_100_MS ) ;
do {
ql4_84xx_ipmdio_rd_reg ( ha , addr1 , addr3 , mask , addr2 , & temp ) ;
if ( ( temp & 0x1 ) ! = 1 )
break ;
if ( time_after_eq ( jiffies , timeout ) ) {
ql4_printk ( KERN_INFO , ha , " Error in processing mdiobus idle \n " ) ;
return QLA_ERROR ;
}
} while ( 1 ) ;
return rval ;
}
static int ql4_84xx_ipmdio_wr_reg ( struct scsi_qla_host * ha ,
uint32_t addr1 , uint32_t addr3 ,
uint32_t mask , uint32_t addr ,
uint32_t value )
{
int rval = QLA_SUCCESS ;
rval = ql4_84xx_poll_wait_for_ready ( ha , addr1 , mask ) ;
if ( rval )
goto exit_ipmdio_wr_reg ;
ha - > isp_ops - > wr_reg_indirect ( ha , addr3 , value ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , addr1 , addr ) ;
rval = ql4_84xx_poll_wait_for_ready ( ha , addr1 , mask ) ;
if ( rval )
goto exit_ipmdio_wr_reg ;
exit_ipmdio_wr_reg :
return rval ;
}
2012-05-18 12:41:44 +04:00
static void qla4_8xxx_minidump_process_rdcrb ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
2012-05-18 12:41:44 +04:00
uint32_t * * d_ptr )
{
uint32_t r_addr , r_stride , loop_cnt , i , r_value ;
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_crb * crb_hdr ;
2012-05-18 12:41:44 +04:00
uint32_t * data_ptr = * d_ptr ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Entering fn: %s \n " , __func__ ) ) ;
2012-08-22 15:55:00 +04:00
crb_hdr = ( struct qla8xxx_minidump_entry_crb * ) entry_hdr ;
2012-05-18 12:41:44 +04:00
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 + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , r_addr , & r_value ) ;
2012-05-18 12:41:44 +04:00
* data_ptr + + = cpu_to_le32 ( r_addr ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
r_addr + = r_stride ;
}
* d_ptr = data_ptr ;
}
2013-08-23 11:40:18 +04:00
static int qla4_83xx_check_dma_engine_state ( struct scsi_qla_host * ha )
{
int rval = QLA_SUCCESS ;
uint32_t dma_eng_num = 0 , cmd_sts_and_cntrl = 0 ;
uint64_t dma_base_addr = 0 ;
struct qla4_8xxx_minidump_template_hdr * tmplt_hdr = NULL ;
tmplt_hdr = ( struct qla4_8xxx_minidump_template_hdr * )
ha - > fw_dump_tmplt_hdr ;
dma_eng_num =
tmplt_hdr - > saved_state_array [ QLA83XX_PEX_DMA_ENGINE_INDEX ] ;
dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
( dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET ) ;
/* Read the pex-dma's command-status-and-control register. */
rval = ha - > isp_ops - > rd_reg_indirect ( ha ,
( dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL ) ,
& cmd_sts_and_cntrl ) ;
if ( rval )
return QLA_ERROR ;
/* Check if requested pex-dma engine is available. */
if ( cmd_sts_and_cntrl & BIT_31 )
return QLA_SUCCESS ;
else
return QLA_ERROR ;
}
static int qla4_83xx_start_pex_dma ( struct scsi_qla_host * ha ,
struct qla4_83xx_minidump_entry_rdmem_pex_dma * m_hdr )
{
int rval = QLA_SUCCESS , wait = 0 ;
uint32_t dma_eng_num = 0 , cmd_sts_and_cntrl = 0 ;
uint64_t dma_base_addr = 0 ;
struct qla4_8xxx_minidump_template_hdr * tmplt_hdr = NULL ;
tmplt_hdr = ( struct qla4_8xxx_minidump_template_hdr * )
ha - > fw_dump_tmplt_hdr ;
dma_eng_num =
tmplt_hdr - > saved_state_array [ QLA83XX_PEX_DMA_ENGINE_INDEX ] ;
dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
( dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET ) ;
rval = ha - > isp_ops - > wr_reg_indirect ( ha ,
dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_LOW ,
m_hdr - > desc_card_addr ) ;
if ( rval )
goto error_exit ;
rval = ha - > isp_ops - > wr_reg_indirect ( ha ,
dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_HIGH , 0 ) ;
if ( rval )
goto error_exit ;
rval = ha - > isp_ops - > wr_reg_indirect ( ha ,
dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL ,
m_hdr - > start_dma_cmd ) ;
if ( rval )
goto error_exit ;
/* Wait for dma operation to complete. */
for ( wait = 0 ; wait < QLA83XX_PEX_DMA_MAX_WAIT ; wait + + ) {
rval = ha - > isp_ops - > rd_reg_indirect ( ha ,
( dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL ) ,
& cmd_sts_and_cntrl ) ;
if ( rval )
goto error_exit ;
if ( ( cmd_sts_and_cntrl & BIT_1 ) = = 0 )
break ;
else
udelay ( 10 ) ;
}
/* Wait a max of 100 ms, otherwise fallback to rdmem entry read */
if ( wait > = QLA83XX_PEX_DMA_MAX_WAIT ) {
rval = QLA_ERROR ;
goto error_exit ;
}
error_exit :
return rval ;
}
2014-02-25 07:07:00 +04:00
static int qla4_8xxx_minidump_pex_dma_read ( struct scsi_qla_host * ha ,
2013-08-23 11:40:18 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
uint32_t * * d_ptr )
{
int rval = QLA_SUCCESS ;
struct qla4_83xx_minidump_entry_rdmem_pex_dma * m_hdr = NULL ;
uint32_t size , read_size ;
uint8_t * data_ptr = ( uint8_t * ) * d_ptr ;
void * rdmem_buffer = NULL ;
dma_addr_t rdmem_dma ;
struct qla4_83xx_pex_dma_descriptor dma_desc ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Entering fn: %s \n " , __func__ ) ) ;
rval = qla4_83xx_check_dma_engine_state ( ha ) ;
if ( rval ! = QLA_SUCCESS ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: DMA engine not available. Fallback to rdmem-read. \n " ,
__func__ ) ) ;
return QLA_ERROR ;
}
m_hdr = ( struct qla4_83xx_minidump_entry_rdmem_pex_dma * ) entry_hdr ;
rdmem_buffer = dma_alloc_coherent ( & ha - > pdev - > dev ,
QLA83XX_PEX_DMA_READ_SIZE ,
& rdmem_dma , GFP_KERNEL ) ;
if ( ! rdmem_buffer ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: Unable to allocate rdmem dma buffer \n " ,
__func__ ) ) ;
return QLA_ERROR ;
}
/* Prepare pex-dma descriptor to be written to MS memory. */
/* dma-desc-cmd layout:
* 0 - 3 : dma - desc - cmd 0 - 3
* 4 - 7 : pcid function number
* 8 - 15 : dma - desc - cmd 8 - 15
*/
dma_desc . cmd . dma_desc_cmd = ( m_hdr - > dma_desc_cmd & 0xff0f ) ;
dma_desc . cmd . dma_desc_cmd | = ( ( PCI_FUNC ( ha - > pdev - > devfn ) & 0xf ) < < 0x4 ) ;
dma_desc . dma_bus_addr = rdmem_dma ;
size = 0 ;
read_size = 0 ;
/*
* Perform rdmem operation using pex - dma .
* Prepare dma in chunks of QLA83XX_PEX_DMA_READ_SIZE .
*/
while ( read_size < m_hdr - > read_data_size ) {
if ( m_hdr - > read_data_size - read_size > =
QLA83XX_PEX_DMA_READ_SIZE )
size = QLA83XX_PEX_DMA_READ_SIZE ;
else {
size = ( m_hdr - > read_data_size - read_size ) ;
if ( rdmem_buffer )
dma_free_coherent ( & ha - > pdev - > dev ,
QLA83XX_PEX_DMA_READ_SIZE ,
rdmem_buffer , rdmem_dma ) ;
rdmem_buffer = dma_alloc_coherent ( & ha - > pdev - > dev , size ,
& rdmem_dma ,
GFP_KERNEL ) ;
if ( ! rdmem_buffer ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: Unable to allocate rdmem dma buffer \n " ,
__func__ ) ) ;
return QLA_ERROR ;
}
dma_desc . dma_bus_addr = rdmem_dma ;
}
dma_desc . src_addr = m_hdr - > read_addr + read_size ;
dma_desc . cmd . read_data_size = size ;
/* Prepare: Write pex-dma descriptor to MS memory. */
2014-02-25 07:07:00 +04:00
rval = qla4_8xxx_ms_mem_write_128b ( ha ,
2013-08-23 11:40:18 +04:00
( uint64_t ) m_hdr - > desc_card_addr ,
( uint32_t * ) & dma_desc ,
( sizeof ( struct qla4_83xx_pex_dma_descriptor ) / 16 ) ) ;
2014-02-25 07:07:02 +04:00
if ( rval ! = QLA_SUCCESS ) {
2013-08-23 11:40:18 +04:00
ql4_printk ( KERN_INFO , ha ,
" %s: Error writing rdmem-dma-init to MS !!! \n " ,
__func__ ) ;
goto error_exit ;
}
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: Dma-desc: Instruct for rdmem dma (size 0x%x). \n " ,
__func__ , size ) ) ;
/* Execute: Start pex-dma operation. */
rval = qla4_83xx_start_pex_dma ( ha , m_hdr ) ;
if ( rval ! = QLA_SUCCESS ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" scsi(%ld): start-pex-dma failed rval=0x%x \n " ,
ha - > host_no , rval ) ) ;
goto error_exit ;
}
memcpy ( data_ptr , rdmem_buffer , size ) ;
data_ptr + = size ;
read_size + = size ;
}
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Leaving fn: %s \n " , __func__ ) ) ;
* d_ptr = ( uint32_t * ) data_ptr ;
error_exit :
if ( rdmem_buffer )
dma_free_coherent ( & ha - > pdev - > dev , size , rdmem_buffer ,
rdmem_dma ) ;
return rval ;
}
2012-05-18 12:41:44 +04:00
static int qla4_8xxx_minidump_process_l2tag ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
2012-05-18 12:41:44 +04:00
uint32_t * * d_ptr )
{
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 ;
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_cache * cache_hdr ;
2012-05-18 12:41:44 +04:00
int rval = QLA_ERROR ;
uint32_t * data_ptr = * d_ptr ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Entering fn: %s \n " , __func__ ) ) ;
2012-08-22 15:55:00 +04:00
cache_hdr = ( struct qla8xxx_minidump_entry_cache * ) entry_hdr ;
2012-05-18 12:41:44 +04:00
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 + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , t_r_addr , t_value ) ;
2012-05-18 12:41:44 +04:00
if ( c_value_w )
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , c_addr , c_value_w ) ;
2012-05-18 12:41:44 +04:00
if ( p_mask ) {
w_time = jiffies + p_wait ;
do {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , c_addr ,
& c_value_r ) ;
2012-05-18 12:41:44 +04:00
if ( ( c_value_r & p_mask ) = = 0 ) {
break ;
} else if ( time_after_eq ( jiffies , w_time ) ) {
/* capturing dump failed */
return rval ;
}
} while ( 1 ) ;
}
addr = r_addr ;
for ( k = 0 ; k < r_cnt ; k + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , addr , & r_value ) ;
2012-05-18 12:41:44 +04:00
* 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 int qla4_8xxx_minidump_process_control ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr )
2012-05-18 12:41:44 +04:00
{
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_crb * crb_entry ;
2012-05-18 12:41:44 +04:00
uint32_t read_value , opcode , poll_time , addr , index , rval = QLA_SUCCESS ;
uint32_t crb_addr ;
unsigned long wtime ;
struct qla4_8xxx_minidump_template_hdr * tmplt_hdr ;
int i ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Entering fn: %s \n " , __func__ ) ) ;
tmplt_hdr = ( struct qla4_8xxx_minidump_template_hdr * )
ha - > fw_dump_tmplt_hdr ;
2012-08-22 15:55:00 +04:00
crb_entry = ( struct qla8xxx_minidump_entry_crb * ) entry_hdr ;
2012-05-18 12:41:44 +04:00
crb_addr = crb_entry - > addr ;
for ( i = 0 ; i < crb_entry - > op_count ; i + + ) {
opcode = crb_entry - > crb_ctrl . opcode ;
2012-08-22 17:14:24 +04:00
if ( opcode & QLA8XXX_DBG_OPCODE_WR ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , crb_addr ,
crb_entry - > value_1 ) ;
2012-08-22 17:14:24 +04:00
opcode & = ~ QLA8XXX_DBG_OPCODE_WR ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 17:14:24 +04:00
if ( opcode & QLA8XXX_DBG_OPCODE_RW ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , crb_addr , & read_value ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , crb_addr , read_value ) ;
2012-08-22 17:14:24 +04:00
opcode & = ~ QLA8XXX_DBG_OPCODE_RW ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 17:14:24 +04:00
if ( opcode & QLA8XXX_DBG_OPCODE_AND ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , crb_addr , & read_value ) ;
2012-05-18 12:41:44 +04:00
read_value & = crb_entry - > value_2 ;
2012-08-22 17:14:24 +04:00
opcode & = ~ QLA8XXX_DBG_OPCODE_AND ;
if ( opcode & QLA8XXX_DBG_OPCODE_OR ) {
2012-05-18 12:41:44 +04:00
read_value | = crb_entry - > value_3 ;
2012-08-22 17:14:24 +04:00
opcode & = ~ QLA8XXX_DBG_OPCODE_OR ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , crb_addr , read_value ) ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 17:14:24 +04:00
if ( opcode & QLA8XXX_DBG_OPCODE_OR ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , crb_addr , & read_value ) ;
2012-05-18 12:41:44 +04:00
read_value | = crb_entry - > value_3 ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , crb_addr , read_value ) ;
2012-08-22 17:14:24 +04:00
opcode & = ~ QLA8XXX_DBG_OPCODE_OR ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 17:14:24 +04:00
if ( opcode & QLA8XXX_DBG_OPCODE_POLL ) {
2012-05-18 12:41:44 +04:00
poll_time = crb_entry - > crb_strd . poll_timeout ;
wtime = jiffies + poll_time ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , crb_addr , & read_value ) ;
2012-05-18 12:41:44 +04:00
do {
if ( ( read_value & crb_entry - > value_2 ) = =
2012-08-22 15:55:04 +04:00
crb_entry - > value_1 ) {
2012-05-18 12:41:44 +04:00
break ;
2012-08-22 15:55:04 +04:00
} else if ( time_after_eq ( jiffies , wtime ) ) {
2012-05-18 12:41:44 +04:00
/* capturing dump failed */
rval = QLA_ERROR ;
break ;
2012-08-22 15:55:04 +04:00
} else {
ha - > isp_ops - > rd_reg_indirect ( ha ,
crb_addr , & read_value ) ;
}
2012-05-18 12:41:44 +04:00
} while ( 1 ) ;
2012-08-22 17:14:24 +04:00
opcode & = ~ QLA8XXX_DBG_OPCODE_POLL ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 17:14:24 +04:00
if ( opcode & QLA8XXX_DBG_OPCODE_RDSTATE ) {
2012-05-18 12:41:44 +04:00
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 ;
}
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , addr , & read_value ) ;
2012-05-18 12:41:44 +04:00
index = crb_entry - > crb_ctrl . state_index_v ;
tmplt_hdr - > saved_state_array [ index ] = read_value ;
2012-08-22 17:14:24 +04:00
opcode & = ~ QLA8XXX_DBG_OPCODE_RDSTATE ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 17:14:24 +04:00
if ( opcode & QLA8XXX_DBG_OPCODE_WRSTATE ) {
2012-05-18 12:41:44 +04:00
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 ;
}
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , addr , read_value ) ;
2012-08-22 17:14:24 +04:00
opcode & = ~ QLA8XXX_DBG_OPCODE_WRSTATE ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 17:14:24 +04:00
if ( opcode & QLA8XXX_DBG_OPCODE_MDSTATE ) {
2012-05-18 12:41:44 +04:00
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 ;
2012-08-22 17:14:24 +04:00
opcode & = ~ QLA8XXX_DBG_OPCODE_MDSTATE ;
2012-05-18 12:41:44 +04:00
}
crb_addr + = crb_entry - > crb_strd . addr_stride ;
}
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Leaving fn: %s \n " , __func__ ) ) ;
return rval ;
}
static void qla4_8xxx_minidump_process_rdocm ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
2012-05-18 12:41:44 +04:00
uint32_t * * d_ptr )
{
uint32_t r_addr , r_stride , loop_cnt , i , r_value ;
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_rdocm * ocm_hdr ;
2012-05-18 12:41:44 +04:00
uint32_t * data_ptr = * d_ptr ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Entering fn: %s \n " , __func__ ) ) ;
2012-08-22 15:55:00 +04:00
ocm_hdr = ( struct qla8xxx_minidump_entry_rdocm * ) entry_hdr ;
2012-05-18 12:41:44 +04:00
r_addr = ocm_hdr - > read_addr ;
r_stride = ocm_hdr - > read_addr_stride ;
loop_cnt = ocm_hdr - > op_count ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" [%s]: r_addr: 0x%x, r_stride: 0x%x, loop_cnt: 0x%x \n " ,
__func__ , r_addr , r_stride , loop_cnt ) ) ;
for ( i = 0 ; i < loop_cnt ; i + + ) {
r_value = readl ( ( void __iomem * ) ( r_addr + ha - > nx_pcibase ) ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
r_addr + = r_stride ;
}
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Leaving fn: %s datacount: 0x%lx \n " ,
2012-08-07 15:57:14 +04:00
__func__ , ( long unsigned int ) ( loop_cnt * sizeof ( uint32_t ) ) ) ) ;
2012-05-18 12:41:44 +04:00
* d_ptr = data_ptr ;
}
static void qla4_8xxx_minidump_process_rdmux ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
2012-05-18 12:41:44 +04:00
uint32_t * * d_ptr )
{
uint32_t r_addr , s_stride , s_addr , s_value , loop_cnt , i , r_value ;
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_mux * mux_hdr ;
2012-05-18 12:41:44 +04:00
uint32_t * data_ptr = * d_ptr ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Entering fn: %s \n " , __func__ ) ) ;
2012-08-22 15:55:00 +04:00
mux_hdr = ( struct qla8xxx_minidump_entry_mux * ) entry_hdr ;
2012-05-18 12:41:44 +04:00
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 + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , s_addr , s_value ) ;
ha - > isp_ops - > rd_reg_indirect ( ha , r_addr , & r_value ) ;
2012-05-18 12:41:44 +04:00
* data_ptr + + = cpu_to_le32 ( s_value ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
s_value + = s_stride ;
}
* d_ptr = data_ptr ;
}
static void qla4_8xxx_minidump_process_l1cache ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
2012-05-18 12:41:44 +04:00
uint32_t * * d_ptr )
{
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 ;
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_cache * cache_hdr ;
2012-05-18 12:41:44 +04:00
uint32_t * data_ptr = * d_ptr ;
2012-08-22 15:55:00 +04:00
cache_hdr = ( struct qla8xxx_minidump_entry_cache * ) entry_hdr ;
2012-05-18 12:41:44 +04:00
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 + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , t_r_addr , t_value ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , c_addr , c_value_w ) ;
2012-05-18 12:41:44 +04:00
addr = r_addr ;
for ( k = 0 ; k < r_cnt ; k + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , addr , & r_value ) ;
2012-05-18 12:41:44 +04:00
* 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 qla4_8xxx_minidump_process_queue ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
2012-05-18 12:41:44 +04:00
uint32_t * * d_ptr )
{
uint32_t s_addr , r_addr ;
uint32_t r_stride , r_value , r_cnt , qid = 0 ;
uint32_t i , k , loop_cnt ;
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_queue * q_hdr ;
2012-05-18 12:41:44 +04:00
uint32_t * data_ptr = * d_ptr ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Entering fn: %s \n " , __func__ ) ) ;
2012-08-22 15:55:00 +04:00
q_hdr = ( struct qla8xxx_minidump_entry_queue * ) entry_hdr ;
2012-05-18 12:41:44 +04:00
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 + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , s_addr , qid ) ;
2012-05-18 12:41:44 +04:00
r_addr = q_hdr - > read_addr ;
for ( k = 0 ; k < r_cnt ; k + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , r_addr , & r_value ) ;
2012-05-18 12:41:44 +04:00
* data_ptr + + = cpu_to_le32 ( r_value ) ;
r_addr + = r_stride ;
}
qid + = q_hdr - > q_strd . queue_id_stride ;
}
* d_ptr = data_ptr ;
}
# define MD_DIRECT_ROM_WINDOW 0x42110030
# define MD_DIRECT_ROM_READ_BASE 0x42150000
2012-08-22 15:54:59 +04:00
static void qla4_82xx_minidump_process_rdrom ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
2012-05-18 12:41:44 +04:00
uint32_t * * d_ptr )
{
uint32_t r_addr , r_value ;
uint32_t i , loop_cnt ;
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_rdrom * rom_hdr ;
2012-05-18 12:41:44 +04:00
uint32_t * data_ptr = * d_ptr ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Entering fn: %s \n " , __func__ ) ) ;
2012-08-22 15:55:00 +04:00
rom_hdr = ( struct qla8xxx_minidump_entry_rdrom * ) entry_hdr ;
2012-05-18 12:41:44 +04:00
r_addr = rom_hdr - > read_addr ;
loop_cnt = rom_hdr - > read_data_size / sizeof ( uint32_t ) ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" [%s]: flash_addr: 0x%x, read_data_size: 0x%x \n " ,
__func__ , r_addr , loop_cnt ) ) ;
for ( i = 0 ; i < loop_cnt ; i + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , MD_DIRECT_ROM_WINDOW ,
( r_addr & 0xFFFF0000 ) ) ;
ha - > isp_ops - > rd_reg_indirect ( ha ,
MD_DIRECT_ROM_READ_BASE + ( r_addr & 0x0000FFFF ) ,
& r_value ) ;
2012-05-18 12:41:44 +04:00
* data_ptr + + = cpu_to_le32 ( r_value ) ;
r_addr + = sizeof ( uint32_t ) ;
}
* d_ptr = data_ptr ;
}
# define MD_MIU_TEST_AGT_CTRL 0x41000090
# define MD_MIU_TEST_AGT_ADDR_LO 0x41000094
# define MD_MIU_TEST_AGT_ADDR_HI 0x41000098
2013-08-23 11:40:18 +04:00
static int __qla4_8xxx_minidump_process_rdmem ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
2012-05-18 12:41:44 +04:00
uint32_t * * d_ptr )
{
uint32_t r_addr , r_value , r_data ;
uint32_t i , j , loop_cnt ;
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_rdmem * m_hdr ;
2012-05-18 12:41:44 +04:00
unsigned long flags ;
uint32_t * data_ptr = * d_ptr ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Entering fn: %s \n " , __func__ ) ) ;
2012-08-22 15:55:00 +04:00
m_hdr = ( struct qla8xxx_minidump_entry_rdmem * ) entry_hdr ;
2012-05-18 12:41:44 +04:00
r_addr = m_hdr - > read_addr ;
loop_cnt = m_hdr - > read_data_size / 16 ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" [%s]: Read addr: 0x%x, read_data_size: 0x%x \n " ,
__func__ , r_addr , m_hdr - > read_data_size ) ) ;
if ( r_addr & 0xf ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2013-03-16 15:53:05 +04:00
" [%s]: Read addr 0x%x not 16 bytes aligned \n " ,
2012-05-18 12:41:44 +04:00
__func__ , r_addr ) ) ;
return QLA_ERROR ;
}
if ( m_hdr - > read_data_size % 16 ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" [%s]: Read data[0x%x] not multiple of 16 bytes \n " ,
__func__ , m_hdr - > read_data_size ) ) ;
return QLA_ERROR ;
}
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" [%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 + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , MD_MIU_TEST_AGT_ADDR_LO ,
r_addr ) ;
2012-05-18 12:41:44 +04:00
r_value = 0 ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , MD_MIU_TEST_AGT_ADDR_HI ,
r_value ) ;
2012-05-18 12:41:44 +04:00
r_value = MIU_TA_CTL_ENABLE ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , MD_MIU_TEST_AGT_CTRL , r_value ) ;
2012-08-22 15:55:03 +04:00
r_value = MIU_TA_CTL_START_ENABLE ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > wr_reg_indirect ( ha , MD_MIU_TEST_AGT_CTRL , r_value ) ;
2012-05-18 12:41:44 +04:00
for ( j = 0 ; j < MAX_CTL_CHECK ; j + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha , MD_MIU_TEST_AGT_CTRL ,
& r_value ) ;
2012-05-18 12:41:44 +04:00
if ( ( r_value & MIU_TA_CTL_BUSY ) = = 0 )
break ;
}
if ( j > = MAX_CTL_CHECK ) {
printk_ratelimited ( KERN_ERR
" %s: failed to read through agent \n " ,
__func__ ) ;
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
return QLA_SUCCESS ;
}
for ( j = 0 ; j < 4 ; j + + ) {
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rd_reg_indirect ( ha ,
MD_MIU_TEST_AGT_RDDATA [ j ] ,
& r_data ) ;
2012-05-18 12:41:44 +04:00
* data_ptr + + = cpu_to_le32 ( r_data ) ;
}
r_addr + = 16 ;
}
write_unlock_irqrestore ( & ha - > hw_lock , flags ) ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Leaving fn: %s datacount: 0x%x \n " ,
__func__ , ( loop_cnt * 16 ) ) ) ;
* d_ptr = data_ptr ;
return QLA_SUCCESS ;
}
2013-08-23 11:40:18 +04:00
static int qla4_8xxx_minidump_process_rdmem ( struct scsi_qla_host * ha ,
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
uint32_t * * d_ptr )
{
uint32_t * data_ptr = * d_ptr ;
int rval = QLA_SUCCESS ;
2014-02-25 07:07:00 +04:00
rval = qla4_8xxx_minidump_pex_dma_read ( ha , entry_hdr , & data_ptr ) ;
if ( rval ! = QLA_SUCCESS )
2013-08-23 11:40:18 +04:00
rval = __qla4_8xxx_minidump_process_rdmem ( ha , entry_hdr ,
& data_ptr ) ;
* d_ptr = data_ptr ;
return rval ;
}
2012-08-22 15:55:01 +04:00
static void qla4_8xxx_mark_entry_skipped ( struct scsi_qla_host * ha ,
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
2012-05-18 12:41:44 +04:00
int index )
{
2012-08-22 17:14:24 +04:00
entry_hdr - > d_ctrl . driver_flags | = QLA8XXX_DBG_SKIPPED_FLAG ;
2012-05-18 12:41:44 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x] \n " ,
ha - > host_no , index , entry_hdr - > entry_type ,
entry_hdr - > d_ctrl . entry_capture_mask ) ) ;
2013-12-16 15:49:44 +04:00
/* If driver encounters a new entry type that it cannot process,
* it should just skip the entry and adjust the total buffer size by
* from subtracting the skipped bytes from it
*/
ha - > fw_dump_skip_size + = entry_hdr - > entry_capture_size ;
2012-05-18 12:41:44 +04:00
}
2012-08-22 15:55:08 +04:00
/* ISP83xx functions to process new minidump entries... */
static uint32_t qla83xx_minidump_process_pollrd ( struct scsi_qla_host * ha ,
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
uint32_t * * d_ptr )
{
uint32_t r_addr , s_addr , s_value , r_value , poll_wait , poll_mask ;
uint16_t s_stride , i ;
uint32_t * data_ptr = * d_ptr ;
uint32_t rval = QLA_SUCCESS ;
struct qla83xx_minidump_entry_pollrd * pollrd_hdr ;
pollrd_hdr = ( struct qla83xx_minidump_entry_pollrd * ) entry_hdr ;
s_addr = le32_to_cpu ( pollrd_hdr - > select_addr ) ;
r_addr = le32_to_cpu ( pollrd_hdr - > read_addr ) ;
s_value = le32_to_cpu ( pollrd_hdr - > select_value ) ;
s_stride = le32_to_cpu ( pollrd_hdr - > select_value_stride ) ;
poll_wait = le32_to_cpu ( pollrd_hdr - > poll_wait ) ;
poll_mask = le32_to_cpu ( pollrd_hdr - > poll_mask ) ;
for ( i = 0 ; i < le32_to_cpu ( pollrd_hdr - > op_count ) ; i + + ) {
ha - > isp_ops - > wr_reg_indirect ( ha , s_addr , s_value ) ;
poll_wait = le32_to_cpu ( pollrd_hdr - > poll_wait ) ;
while ( 1 ) {
ha - > isp_ops - > rd_reg_indirect ( ha , s_addr , & r_value ) ;
if ( ( r_value & poll_mask ) ! = 0 ) {
break ;
} else {
msleep ( 1 ) ;
if ( - - poll_wait = = 0 ) {
ql4_printk ( KERN_ERR , ha , " %s: TIMEOUT \n " ,
__func__ ) ;
rval = QLA_ERROR ;
goto exit_process_pollrd ;
}
}
}
ha - > isp_ops - > rd_reg_indirect ( ha , r_addr , & r_value ) ;
* data_ptr + + = cpu_to_le32 ( s_value ) ;
* data_ptr + + = cpu_to_le32 ( r_value ) ;
s_value + = s_stride ;
}
* d_ptr = data_ptr ;
exit_process_pollrd :
return rval ;
}
2014-02-25 07:06:59 +04:00
static uint32_t qla4_84xx_minidump_process_rddfe ( struct scsi_qla_host * ha ,
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
uint32_t * * d_ptr )
{
int loop_cnt ;
uint32_t addr1 , addr2 , value , data , temp , wrval ;
uint8_t stride , stride2 ;
uint16_t count ;
uint32_t poll , mask , data_size , modify_mask ;
uint32_t wait_count = 0 ;
uint32_t * data_ptr = * d_ptr ;
struct qla8044_minidump_entry_rddfe * rddfe ;
uint32_t rval = QLA_SUCCESS ;
rddfe = ( struct qla8044_minidump_entry_rddfe * ) entry_hdr ;
addr1 = le32_to_cpu ( rddfe - > addr_1 ) ;
value = le32_to_cpu ( rddfe - > value ) ;
stride = le32_to_cpu ( rddfe - > stride ) ;
stride2 = le32_to_cpu ( rddfe - > stride2 ) ;
count = le32_to_cpu ( rddfe - > count ) ;
poll = le32_to_cpu ( rddfe - > poll ) ;
mask = le32_to_cpu ( rddfe - > mask ) ;
modify_mask = le32_to_cpu ( rddfe - > modify_mask ) ;
data_size = le32_to_cpu ( rddfe - > data_size ) ;
addr2 = addr1 + stride ;
for ( loop_cnt = 0x0 ; loop_cnt < count ; loop_cnt + + ) {
ha - > isp_ops - > wr_reg_indirect ( ha , addr1 , ( 0x40000000 | value ) ) ;
wait_count = 0 ;
while ( wait_count < poll ) {
ha - > isp_ops - > rd_reg_indirect ( ha , addr1 , & temp ) ;
if ( ( temp & mask ) ! = 0 )
break ;
wait_count + + ;
}
if ( wait_count = = poll ) {
ql4_printk ( KERN_ERR , ha , " %s: TIMEOUT \n " , __func__ ) ;
rval = QLA_ERROR ;
goto exit_process_rddfe ;
} else {
ha - > isp_ops - > rd_reg_indirect ( ha , addr2 , & temp ) ;
temp = temp & modify_mask ;
temp = ( temp | ( ( loop_cnt < < 16 ) | loop_cnt ) ) ;
wrval = ( ( temp < < 16 ) | temp ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , addr2 , wrval ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , addr1 , value ) ;
wait_count = 0 ;
while ( wait_count < poll ) {
ha - > isp_ops - > rd_reg_indirect ( ha , addr1 , & temp ) ;
if ( ( temp & mask ) ! = 0 )
break ;
wait_count + + ;
}
if ( wait_count = = poll ) {
ql4_printk ( KERN_ERR , ha , " %s: TIMEOUT \n " ,
__func__ ) ;
rval = QLA_ERROR ;
goto exit_process_rddfe ;
}
ha - > isp_ops - > wr_reg_indirect ( ha , addr1 ,
( ( 0x40000000 | value ) +
stride2 ) ) ;
wait_count = 0 ;
while ( wait_count < poll ) {
ha - > isp_ops - > rd_reg_indirect ( ha , addr1 , & temp ) ;
if ( ( temp & mask ) ! = 0 )
break ;
wait_count + + ;
}
if ( wait_count = = poll ) {
ql4_printk ( KERN_ERR , ha , " %s: TIMEOUT \n " ,
__func__ ) ;
rval = QLA_ERROR ;
goto exit_process_rddfe ;
}
ha - > isp_ops - > rd_reg_indirect ( ha , addr2 , & data ) ;
* data_ptr + + = cpu_to_le32 ( wrval ) ;
* data_ptr + + = cpu_to_le32 ( data ) ;
}
}
* d_ptr = data_ptr ;
exit_process_rddfe :
return rval ;
}
static uint32_t qla4_84xx_minidump_process_rdmdio ( struct scsi_qla_host * ha ,
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
uint32_t * * d_ptr )
{
int rval = QLA_SUCCESS ;
uint32_t addr1 , addr2 , value1 , value2 , data , selval ;
uint8_t stride1 , stride2 ;
uint32_t addr3 , addr4 , addr5 , addr6 , addr7 ;
uint16_t count , loop_cnt ;
uint32_t poll , mask ;
uint32_t * data_ptr = * d_ptr ;
struct qla8044_minidump_entry_rdmdio * rdmdio ;
rdmdio = ( struct qla8044_minidump_entry_rdmdio * ) entry_hdr ;
addr1 = le32_to_cpu ( rdmdio - > addr_1 ) ;
addr2 = le32_to_cpu ( rdmdio - > addr_2 ) ;
value1 = le32_to_cpu ( rdmdio - > value_1 ) ;
stride1 = le32_to_cpu ( rdmdio - > stride_1 ) ;
stride2 = le32_to_cpu ( rdmdio - > stride_2 ) ;
count = le32_to_cpu ( rdmdio - > count ) ;
poll = le32_to_cpu ( rdmdio - > poll ) ;
mask = le32_to_cpu ( rdmdio - > mask ) ;
value2 = le32_to_cpu ( rdmdio - > value_2 ) ;
addr3 = addr1 + stride1 ;
for ( loop_cnt = 0 ; loop_cnt < count ; loop_cnt + + ) {
rval = ql4_84xx_poll_wait_ipmdio_bus_idle ( ha , addr1 , addr2 ,
addr3 , mask ) ;
if ( rval )
goto exit_process_rdmdio ;
addr4 = addr2 - stride1 ;
rval = ql4_84xx_ipmdio_wr_reg ( ha , addr1 , addr3 , mask , addr4 ,
value2 ) ;
if ( rval )
goto exit_process_rdmdio ;
addr5 = addr2 - ( 2 * stride1 ) ;
rval = ql4_84xx_ipmdio_wr_reg ( ha , addr1 , addr3 , mask , addr5 ,
value1 ) ;
if ( rval )
goto exit_process_rdmdio ;
addr6 = addr2 - ( 3 * stride1 ) ;
rval = ql4_84xx_ipmdio_wr_reg ( ha , addr1 , addr3 , mask ,
addr6 , 0x2 ) ;
if ( rval )
goto exit_process_rdmdio ;
rval = ql4_84xx_poll_wait_ipmdio_bus_idle ( ha , addr1 , addr2 ,
addr3 , mask ) ;
if ( rval )
goto exit_process_rdmdio ;
addr7 = addr2 - ( 4 * stride1 ) ;
rval = ql4_84xx_ipmdio_rd_reg ( ha , addr1 , addr3 ,
mask , addr7 , & data ) ;
if ( rval )
goto exit_process_rdmdio ;
selval = ( value2 < < 18 ) | ( value1 < < 2 ) | 2 ;
stride2 = le32_to_cpu ( rdmdio - > stride_2 ) ;
* data_ptr + + = cpu_to_le32 ( selval ) ;
* data_ptr + + = cpu_to_le32 ( data ) ;
value1 = value1 + stride2 ;
* d_ptr = data_ptr ;
}
exit_process_rdmdio :
return rval ;
}
static uint32_t qla4_84xx_minidump_process_pollwr ( struct scsi_qla_host * ha ,
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
uint32_t * * d_ptr )
{
uint32_t addr1 , addr2 , value1 , value2 , poll , mask , r_value ;
struct qla8044_minidump_entry_pollwr * pollwr_hdr ;
uint32_t wait_count = 0 ;
uint32_t rval = QLA_SUCCESS ;
pollwr_hdr = ( struct qla8044_minidump_entry_pollwr * ) entry_hdr ;
addr1 = le32_to_cpu ( pollwr_hdr - > addr_1 ) ;
addr2 = le32_to_cpu ( pollwr_hdr - > addr_2 ) ;
value1 = le32_to_cpu ( pollwr_hdr - > value_1 ) ;
value2 = le32_to_cpu ( pollwr_hdr - > value_2 ) ;
poll = le32_to_cpu ( pollwr_hdr - > poll ) ;
mask = le32_to_cpu ( pollwr_hdr - > mask ) ;
while ( wait_count < poll ) {
ha - > isp_ops - > rd_reg_indirect ( ha , addr1 , & r_value ) ;
if ( ( r_value & poll ) ! = 0 )
break ;
wait_count + + ;
}
if ( wait_count = = poll ) {
ql4_printk ( KERN_ERR , ha , " %s: TIMEOUT \n " , __func__ ) ;
rval = QLA_ERROR ;
goto exit_process_pollwr ;
}
ha - > isp_ops - > wr_reg_indirect ( ha , addr2 , value2 ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , addr1 , value1 ) ;
wait_count = 0 ;
while ( wait_count < poll ) {
ha - > isp_ops - > rd_reg_indirect ( ha , addr1 , & r_value ) ;
if ( ( r_value & poll ) ! = 0 )
break ;
wait_count + + ;
}
exit_process_pollwr :
return rval ;
}
2012-08-22 15:55:08 +04:00
static void qla83xx_minidump_process_rdmux2 ( struct scsi_qla_host * ha ,
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
uint32_t * * d_ptr )
{
uint32_t sel_val1 , sel_val2 , t_sel_val , data , i ;
uint32_t sel_addr1 , sel_addr2 , sel_val_mask , read_addr ;
struct qla83xx_minidump_entry_rdmux2 * rdmux2_hdr ;
uint32_t * data_ptr = * d_ptr ;
rdmux2_hdr = ( struct qla83xx_minidump_entry_rdmux2 * ) entry_hdr ;
sel_val1 = le32_to_cpu ( rdmux2_hdr - > select_value_1 ) ;
sel_val2 = le32_to_cpu ( rdmux2_hdr - > select_value_2 ) ;
sel_addr1 = le32_to_cpu ( rdmux2_hdr - > select_addr_1 ) ;
sel_addr2 = le32_to_cpu ( rdmux2_hdr - > select_addr_2 ) ;
sel_val_mask = le32_to_cpu ( rdmux2_hdr - > select_value_mask ) ;
read_addr = le32_to_cpu ( rdmux2_hdr - > read_addr ) ;
for ( i = 0 ; i < rdmux2_hdr - > op_count ; i + + ) {
ha - > isp_ops - > wr_reg_indirect ( ha , sel_addr1 , sel_val1 ) ;
t_sel_val = sel_val1 & sel_val_mask ;
* data_ptr + + = cpu_to_le32 ( t_sel_val ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , sel_addr2 , t_sel_val ) ;
ha - > isp_ops - > rd_reg_indirect ( ha , read_addr , & data ) ;
* data_ptr + + = cpu_to_le32 ( data ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , sel_addr1 , sel_val2 ) ;
t_sel_val = sel_val2 & sel_val_mask ;
* data_ptr + + = cpu_to_le32 ( t_sel_val ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , sel_addr2 , t_sel_val ) ;
ha - > isp_ops - > rd_reg_indirect ( ha , read_addr , & data ) ;
* data_ptr + + = cpu_to_le32 ( data ) ;
sel_val1 + = rdmux2_hdr - > select_value_stride ;
sel_val2 + = rdmux2_hdr - > select_value_stride ;
}
* d_ptr = data_ptr ;
}
static uint32_t qla83xx_minidump_process_pollrdmwr ( struct scsi_qla_host * ha ,
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
uint32_t * * d_ptr )
{
uint32_t poll_wait , poll_mask , r_value , data ;
uint32_t addr_1 , addr_2 , value_1 , value_2 ;
uint32_t * data_ptr = * d_ptr ;
uint32_t rval = QLA_SUCCESS ;
struct qla83xx_minidump_entry_pollrdmwr * poll_hdr ;
poll_hdr = ( struct qla83xx_minidump_entry_pollrdmwr * ) entry_hdr ;
addr_1 = le32_to_cpu ( poll_hdr - > addr_1 ) ;
addr_2 = le32_to_cpu ( poll_hdr - > addr_2 ) ;
value_1 = le32_to_cpu ( poll_hdr - > value_1 ) ;
value_2 = le32_to_cpu ( poll_hdr - > value_2 ) ;
poll_mask = le32_to_cpu ( poll_hdr - > poll_mask ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , addr_1 , value_1 ) ;
poll_wait = le32_to_cpu ( poll_hdr - > poll_wait ) ;
while ( 1 ) {
ha - > isp_ops - > rd_reg_indirect ( ha , addr_1 , & r_value ) ;
if ( ( r_value & poll_mask ) ! = 0 ) {
break ;
} else {
msleep ( 1 ) ;
if ( - - poll_wait = = 0 ) {
ql4_printk ( KERN_ERR , ha , " %s: TIMEOUT_1 \n " ,
__func__ ) ;
rval = QLA_ERROR ;
goto exit_process_pollrdmwr ;
}
}
}
ha - > isp_ops - > rd_reg_indirect ( ha , addr_2 , & data ) ;
data & = le32_to_cpu ( poll_hdr - > modify_mask ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , addr_2 , data ) ;
ha - > isp_ops - > wr_reg_indirect ( ha , addr_1 , value_2 ) ;
poll_wait = le32_to_cpu ( poll_hdr - > poll_wait ) ;
while ( 1 ) {
ha - > isp_ops - > rd_reg_indirect ( ha , addr_1 , & r_value ) ;
if ( ( r_value & poll_mask ) ! = 0 ) {
break ;
} else {
msleep ( 1 ) ;
if ( - - poll_wait = = 0 ) {
ql4_printk ( KERN_ERR , ha , " %s: TIMEOUT_2 \n " ,
__func__ ) ;
rval = QLA_ERROR ;
goto exit_process_pollrdmwr ;
}
}
}
* data_ptr + + = cpu_to_le32 ( addr_2 ) ;
* data_ptr + + = cpu_to_le32 ( data ) ;
* d_ptr = data_ptr ;
exit_process_pollrdmwr :
return rval ;
}
static uint32_t qla4_83xx_minidump_process_rdrom ( struct scsi_qla_host * ha ,
struct qla8xxx_minidump_entry_hdr * entry_hdr ,
uint32_t * * d_ptr )
{
uint32_t fl_addr , u32_count , rval ;
struct qla8xxx_minidump_entry_rdrom * rom_hdr ;
uint32_t * data_ptr = * d_ptr ;
rom_hdr = ( struct qla8xxx_minidump_entry_rdrom * ) entry_hdr ;
fl_addr = le32_to_cpu ( rom_hdr - > read_addr ) ;
u32_count = le32_to_cpu ( rom_hdr - > read_data_size ) / sizeof ( uint32_t ) ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " [%s]: fl_addr: 0x%x, count: 0x%x \n " ,
__func__ , fl_addr , u32_count ) ) ;
rval = qla4_83xx_lockless_flash_read_u32 ( ha , fl_addr ,
( u8 * ) ( data_ptr ) , u32_count ) ;
if ( rval = = QLA_ERROR ) {
ql4_printk ( KERN_ERR , ha , " %s: Flash Read Error,Count=%d \n " ,
__func__ , u32_count ) ;
goto exit_process_rdrom ;
}
data_ptr + = u32_count ;
* d_ptr = data_ptr ;
exit_process_rdrom :
return rval ;
}
2012-05-18 12:41:44 +04:00
/**
2012-08-22 15:54:59 +04:00
* qla4_8xxx_collect_md_data - Retrieve firmware minidump data .
2012-05-18 12:41:44 +04:00
* @ ha : pointer to adapter structure
* */
static int qla4_8xxx_collect_md_data ( struct scsi_qla_host * ha )
{
int num_entry_hdr = 0 ;
2012-08-22 15:55:00 +04:00
struct qla8xxx_minidump_entry_hdr * entry_hdr ;
2012-05-18 12:41:44 +04:00
struct qla4_8xxx_minidump_template_hdr * tmplt_hdr ;
uint32_t * data_ptr ;
uint32_t data_collected = 0 ;
int i , rval = QLA_ERROR ;
uint64_t now ;
uint32_t timestamp ;
2013-12-16 15:49:44 +04:00
ha - > fw_dump_skip_size = 0 ;
2012-05-18 12:41:44 +04:00
if ( ! ha - > fw_dump ) {
ql4_printk ( KERN_INFO , ha , " %s(%ld) No buffer to dump \n " ,
__func__ , ha - > host_no ) ;
return rval ;
}
tmplt_hdr = ( struct qla4_8xxx_minidump_template_hdr * )
ha - > fw_dump_tmplt_hdr ;
data_ptr = ( uint32_t * ) ( ( uint8_t * ) ha - > fw_dump +
ha - > fw_dump_tmplt_size ) ;
data_collected + = ha - > fw_dump_tmplt_size ;
num_entry_hdr = tmplt_hdr - > num_of_entries ;
ql4_printk ( KERN_INFO , ha , " [%s]: starting data ptr: %p \n " ,
__func__ , data_ptr ) ;
ql4_printk ( KERN_INFO , ha ,
" [%s]: no of entry headers in Template: 0x%x \n " ,
__func__ , num_entry_hdr ) ;
ql4_printk ( KERN_INFO , ha , " [%s]: Capture Mask obtained: 0x%x \n " ,
__func__ , ha - > fw_dump_capture_mask ) ;
ql4_printk ( KERN_INFO , ha , " [%s]: Total_data_size 0x%x, %d obtained \n " ,
__func__ , ha - > fw_dump_size , ha - > fw_dump_size ) ;
/* Update current timestamp before taking dump */
now = get_jiffies_64 ( ) ;
timestamp = ( u32 ) ( jiffies_to_msecs ( now ) / 1000 ) ;
tmplt_hdr - > driver_timestamp = timestamp ;
2012-08-22 15:55:00 +04:00
entry_hdr = ( struct qla8xxx_minidump_entry_hdr * )
2012-05-18 12:41:44 +04:00
( ( ( uint8_t * ) ha - > fw_dump_tmplt_hdr ) +
tmplt_hdr - > first_entry_offset ) ;
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) )
2012-08-22 15:55:08 +04:00
tmplt_hdr - > saved_state_array [ QLA83XX_SS_OCM_WNDREG_INDEX ] =
tmplt_hdr - > ocm_window_reg [ ha - > func_num ] ;
2012-05-18 12:41:44 +04:00
/* Walk through the entry headers - validate/perform required action */
for ( i = 0 ; i < num_entry_hdr ; i + + ) {
2013-08-23 11:40:19 +04:00
if ( data_collected > ha - > fw_dump_size ) {
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha ,
" Data collected: [0x%x], Total Dump size: [0x%x] \n " ,
data_collected , ha - > fw_dump_size ) ;
return rval ;
}
if ( ! ( entry_hdr - > d_ctrl . entry_capture_mask &
ha - > fw_dump_capture_mask ) ) {
entry_hdr - > d_ctrl . driver_flags | =
2012-08-22 17:14:24 +04:00
QLA8XXX_DBG_SKIPPED_FLAG ;
2012-05-18 12:41:44 +04:00
goto skip_nxt_entry ;
}
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" Data collected: [0x%x], Dump size left:[0x%x] \n " ,
data_collected ,
( ha - > fw_dump_size - data_collected ) ) ) ;
/* Decode the entry type and take required action to capture
* debug data
*/
switch ( entry_hdr - > entry_type ) {
2012-08-22 17:14:24 +04:00
case QLA8XXX_RDEND :
2012-08-22 15:55:01 +04:00
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
2012-05-18 12:41:44 +04:00
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_CNTRL :
2012-05-18 12:41:44 +04:00
rval = qla4_8xxx_minidump_process_control ( ha ,
entry_hdr ) ;
if ( rval ! = QLA_SUCCESS ) {
2012-08-22 15:55:01 +04:00
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
2012-05-18 12:41:44 +04:00
goto md_failed ;
}
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_RDCRB :
2012-05-18 12:41:44 +04:00
qla4_8xxx_minidump_process_rdcrb ( ha , entry_hdr ,
& data_ptr ) ;
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_RDMEM :
2012-05-18 12:41:44 +04:00
rval = qla4_8xxx_minidump_process_rdmem ( ha , entry_hdr ,
& data_ptr ) ;
if ( rval ! = QLA_SUCCESS ) {
2012-08-22 15:55:01 +04:00
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
2012-05-18 12:41:44 +04:00
goto md_failed ;
}
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_BOARD :
case QLA8XXX_RDROM :
2012-08-22 15:55:08 +04:00
if ( is_qla8022 ( ha ) ) {
qla4_82xx_minidump_process_rdrom ( ha , entry_hdr ,
& data_ptr ) ;
2013-08-16 15:03:02 +04:00
} else if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) ) {
2012-08-22 15:55:08 +04:00
rval = qla4_83xx_minidump_process_rdrom ( ha ,
entry_hdr ,
& data_ptr ) ;
if ( rval ! = QLA_SUCCESS )
qla4_8xxx_mark_entry_skipped ( ha ,
entry_hdr ,
i ) ;
}
2012-05-18 12:41:44 +04:00
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_L2DTG :
case QLA8XXX_L2ITG :
case QLA8XXX_L2DAT :
case QLA8XXX_L2INS :
2012-05-18 12:41:44 +04:00
rval = qla4_8xxx_minidump_process_l2tag ( ha , entry_hdr ,
& data_ptr ) ;
if ( rval ! = QLA_SUCCESS ) {
2012-08-22 15:55:01 +04:00
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
2012-05-18 12:41:44 +04:00
goto md_failed ;
}
break ;
2012-08-22 15:55:08 +04:00
case QLA8XXX_L1DTG :
case QLA8XXX_L1ITG :
2012-08-22 17:14:24 +04:00
case QLA8XXX_L1DAT :
case QLA8XXX_L1INS :
2012-05-18 12:41:44 +04:00
qla4_8xxx_minidump_process_l1cache ( ha , entry_hdr ,
& data_ptr ) ;
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_RDOCM :
2012-05-18 12:41:44 +04:00
qla4_8xxx_minidump_process_rdocm ( ha , entry_hdr ,
& data_ptr ) ;
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_RDMUX :
2012-05-18 12:41:44 +04:00
qla4_8xxx_minidump_process_rdmux ( ha , entry_hdr ,
& data_ptr ) ;
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_QUEUE :
2012-05-18 12:41:44 +04:00
qla4_8xxx_minidump_process_queue ( ha , entry_hdr ,
& data_ptr ) ;
break ;
2012-08-22 15:55:08 +04:00
case QLA83XX_POLLRD :
2013-08-16 15:03:02 +04:00
if ( is_qla8022 ( ha ) ) {
2012-08-22 15:55:08 +04:00
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
break ;
}
rval = qla83xx_minidump_process_pollrd ( ha , entry_hdr ,
& data_ptr ) ;
if ( rval ! = QLA_SUCCESS )
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
break ;
case QLA83XX_RDMUX2 :
2013-08-16 15:03:02 +04:00
if ( is_qla8022 ( ha ) ) {
2012-08-22 15:55:08 +04:00
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
break ;
}
qla83xx_minidump_process_rdmux2 ( ha , entry_hdr ,
& data_ptr ) ;
break ;
case QLA83XX_POLLRDMWR :
2013-08-16 15:03:02 +04:00
if ( is_qla8022 ( ha ) ) {
2012-08-22 15:55:08 +04:00
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
break ;
}
rval = qla83xx_minidump_process_pollrdmwr ( ha , entry_hdr ,
& data_ptr ) ;
if ( rval ! = QLA_SUCCESS )
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
break ;
2014-02-25 07:06:59 +04:00
case QLA8044_RDDFE :
rval = qla4_84xx_minidump_process_rddfe ( ha , entry_hdr ,
& data_ptr ) ;
if ( rval ! = QLA_SUCCESS )
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
break ;
case QLA8044_RDMDIO :
rval = qla4_84xx_minidump_process_rdmdio ( ha , entry_hdr ,
& data_ptr ) ;
if ( rval ! = QLA_SUCCESS )
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
break ;
case QLA8044_POLLWR :
rval = qla4_84xx_minidump_process_pollwr ( ha , entry_hdr ,
& data_ptr ) ;
if ( rval ! = QLA_SUCCESS )
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_RDNOP :
2012-05-18 12:41:44 +04:00
default :
2012-08-22 15:55:01 +04:00
qla4_8xxx_mark_entry_skipped ( ha , entry_hdr , i ) ;
2012-05-18 12:41:44 +04:00
break ;
}
2013-08-23 11:40:19 +04:00
data_collected = ( uint8_t * ) data_ptr - ( uint8_t * ) ha - > fw_dump ;
2012-05-18 12:41:44 +04:00
skip_nxt_entry :
/* next entry in the template */
2012-08-22 15:55:00 +04:00
entry_hdr = ( struct qla8xxx_minidump_entry_hdr * )
2012-05-18 12:41:44 +04:00
( ( ( uint8_t * ) entry_hdr ) +
entry_hdr - > entry_size ) ;
}
2013-12-16 15:49:44 +04:00
if ( ( data_collected + ha - > fw_dump_skip_size ) ! = ha - > fw_dump_size ) {
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha ,
" Dump data mismatch: Data collected: [0x%x], total_data_size:[0x%x] \n " ,
data_collected , ha - > fw_dump_size ) ;
2013-08-23 11:40:20 +04:00
rval = QLA_ERROR ;
2012-05-18 12:41:44 +04:00
goto md_failed ;
}
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Leaving fn: %s Last entry: 0x%x \n " ,
__func__ , i ) ) ;
md_failed :
return rval ;
}
/**
* qla4_8xxx_uevent_emit - Send uevent when the firmware dump is ready .
* @ ha : pointer to adapter structure
* */
static void qla4_8xxx_uevent_emit ( struct scsi_qla_host * ha , u32 code )
{
char event_string [ 40 ] ;
char * envp [ ] = { event_string , NULL } ;
switch ( code ) {
case QL4_UEVENT_CODE_FW_DUMP :
snprintf ( event_string , sizeof ( event_string ) , " FW_DUMP=%ld " ,
ha - > host_no ) ;
break ;
default :
/*do nothing*/
break ;
}
kobject_uevent_env ( & ( & ha - > pdev - > dev ) - > kobj , KOBJ_CHANGE , envp ) ;
}
2012-08-22 15:55:08 +04:00
void qla4_8xxx_get_minidump ( struct scsi_qla_host * ha )
2012-08-22 15:55:07 +04:00
{
if ( ql4xenablemd & & test_bit ( AF_FW_RECOVERY , & ha - > flags ) & &
! test_bit ( AF_82XX_FW_DUMPED , & ha - > flags ) ) {
if ( ! qla4_8xxx_collect_md_data ( ha ) ) {
qla4_8xxx_uevent_emit ( ha , QL4_UEVENT_CODE_FW_DUMP ) ;
set_bit ( AF_82XX_FW_DUMPED , & ha - > flags ) ;
} else {
ql4_printk ( KERN_INFO , ha , " %s: Unable to collect minidump \n " ,
__func__ ) ;
}
}
}
2010-07-28 14:23:44 +04:00
/**
* qla4_8xxx_device_bootstrap - Initialize device , set DEV_READY , start fw
* @ ha : pointer to adapter structure
*
* Note : IDC lock must be held upon entry
* */
2012-08-22 15:55:08 +04:00
int qla4_8xxx_device_bootstrap ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
2010-10-07 09:50:51 +04:00
int rval = QLA_ERROR ;
2013-12-16 15:49:37 +04:00
int i ;
2013-12-16 15:49:34 +04:00
uint32_t old_count , count ;
[SCSI] qla4xxx: Reduce rom-lock contention during reset recovery.
Issue:
Driver holds rom-lock for too long during reset recovery.
During adapter reset testing, it was found that the driver
holds the rom-lock for too long, because of which other
drivers fail to acquire the rom-lock, leading to reset
failures.
The primary cause is, in the bootstrap code, while
holding the rom-lock, the driver checks if the peg is
halted, causing a 2 second contention.
Fix:
When a reset recovery starts, the driver deduces the cause, and
sets appropriate flags in watchdog & recover_adapter routines.
This flag should be used to determine if bootstrap is invoked
from probe or reset context, reducing the rom-lock footprint of
the drivers.
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2013-12-16 15:49:45 +04:00
int need_reset = 0 ;
2010-07-28 14:23:44 +04:00
2012-08-22 15:55:04 +04:00
need_reset = ha - > isp_ops - > need_reset ( ha ) ;
2010-10-07 09:50:51 +04:00
if ( need_reset ) {
/* We are trying to perform a recovery here. */
[SCSI] qla4xxx: Reduce rom-lock contention during reset recovery.
Issue:
Driver holds rom-lock for too long during reset recovery.
During adapter reset testing, it was found that the driver
holds the rom-lock for too long, because of which other
drivers fail to acquire the rom-lock, leading to reset
failures.
The primary cause is, in the bootstrap code, while
holding the rom-lock, the driver checks if the peg is
halted, causing a 2 second contention.
Fix:
When a reset recovery starts, the driver deduces the cause, and
sets appropriate flags in watchdog & recover_adapter routines.
This flag should be used to determine if bootstrap is invoked
from probe or reset context, reducing the rom-lock footprint of
the drivers.
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2013-12-16 15:49:45 +04:00
if ( test_bit ( AF_FW_RECOVERY , & ha - > flags ) )
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > rom_lock_recovery ( ha ) ;
2010-10-07 09:50:51 +04:00
} else {
[SCSI] qla4xxx: Reduce rom-lock contention during reset recovery.
Issue:
Driver holds rom-lock for too long during reset recovery.
During adapter reset testing, it was found that the driver
holds the rom-lock for too long, because of which other
drivers fail to acquire the rom-lock, leading to reset
failures.
The primary cause is, in the bootstrap code, while
holding the rom-lock, the driver checks if the peg is
halted, causing a 2 second contention.
Fix:
When a reset recovery starts, the driver deduces the cause, and
sets appropriate flags in watchdog & recover_adapter routines.
This flag should be used to determine if bootstrap is invoked
from probe or reset context, reducing the rom-lock footprint of
the drivers.
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2013-12-16 15:49:45 +04:00
old_count = qla4_8xxx_rd_direct ( ha , QLA8XXX_PEG_ALIVE_COUNTER ) ;
for ( i = 0 ; i < 10 ; i + + ) {
msleep ( 200 ) ;
count = qla4_8xxx_rd_direct ( ha ,
QLA8XXX_PEG_ALIVE_COUNTER ) ;
if ( count ! = old_count ) {
rval = QLA_SUCCESS ;
goto dev_ready ;
}
2010-10-07 09:50:51 +04:00
}
[SCSI] qla4xxx: Reduce rom-lock contention during reset recovery.
Issue:
Driver holds rom-lock for too long during reset recovery.
During adapter reset testing, it was found that the driver
holds the rom-lock for too long, because of which other
drivers fail to acquire the rom-lock, leading to reset
failures.
The primary cause is, in the bootstrap code, while
holding the rom-lock, the driver checks if the peg is
halted, causing a 2 second contention.
Fix:
When a reset recovery starts, the driver deduces the cause, and
sets appropriate flags in watchdog & recover_adapter routines.
This flag should be used to determine if bootstrap is invoked
from probe or reset context, reducing the rom-lock footprint of
the drivers.
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2013-12-16 15:49:45 +04:00
ha - > isp_ops - > rom_lock_recovery ( ha ) ;
2010-07-28 14:23:44 +04:00
}
/* set to DEV_INITIALIZING */
ql4_printk ( KERN_INFO , ha , " HW State: INITIALIZING \n " ) ;
2012-08-22 15:55:04 +04:00
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DEV_STATE ,
QLA8XXX_DEV_INITIALIZING ) ;
2010-07-28 14:23:44 +04:00
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_unlock ( ha ) ;
2012-08-22 15:55:08 +04:00
if ( is_qla8022 ( ha ) )
qla4_8xxx_get_minidump ( ha ) ;
2012-08-22 15:55:04 +04:00
rval = ha - > isp_ops - > restart_firmware ( ha ) ;
ha - > isp_ops - > idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
if ( rval ! = QLA_SUCCESS ) {
ql4_printk ( KERN_INFO , ha , " HW State: FAILED \n " ) ;
qla4_8xxx_clear_drv_active ( ha ) ;
2012-08-22 15:55:04 +04:00
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DEV_STATE ,
QLA8XXX_DEV_FAILED ) ;
2010-07-28 14:23:44 +04:00
return rval ;
}
dev_ready :
ql4_printk ( KERN_INFO , ha , " HW State: READY \n " ) ;
2012-08-22 15:55:04 +04:00
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DEV_STATE , QLA8XXX_DEV_READY ) ;
2010-07-28 14:23:44 +04:00
2010-10-07 09:50:51 +04:00
return rval ;
2010-07-28 14:23:44 +04:00
}
/**
2012-08-22 15:54:59 +04:00
* qla4_82xx_need_reset_handler - Code to start reset sequence
2010-07-28 14:23:44 +04:00
* @ ha : pointer to adapter structure
*
* Note : IDC lock must be held upon entry
* */
static void
2012-08-22 15:54:59 +04:00
qla4_82xx_need_reset_handler ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
uint32_t dev_state , drv_state , drv_active ;
2012-05-18 12:41:44 +04:00
uint32_t active_mask = 0xFFFFFFFF ;
2010-07-28 14:23:44 +04:00
unsigned long reset_timeout ;
ql4_printk ( KERN_INFO , ha ,
" Performing ISP error recovery \n " ) ;
if ( test_and_clear_bit ( AF_ONLINE , & ha - > flags ) ) {
2012-08-22 15:54:59 +04:00
qla4_82xx_idc_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
ha - > isp_ops - > disable_intrs ( ha ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
}
2012-08-22 17:14:24 +04:00
if ( ! test_bit ( AF_8XXX_RST_OWNER , & ha - > flags ) ) {
2012-05-18 12:41:44 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s(%ld): reset acknowledged \n " ,
__func__ , ha - > host_no ) ) ;
qla4_8xxx_set_rst_ready ( ha ) ;
} else {
active_mask = ( ~ ( 1 < < ( ha - > func_num * 4 ) ) ) ;
}
2010-07-28 14:23:44 +04:00
/* wait for 10 seconds for reset ack from all functions */
reset_timeout = jiffies + ( ha - > nx_reset_timeout * HZ ) ;
2012-08-22 15:54:59 +04:00
drv_state = qla4_82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
drv_active = qla4_82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
2010-07-28 14:23:44 +04:00
ql4_printk ( KERN_INFO , ha ,
" %s(%ld): drv_state = 0x%x, drv_active = 0x%x \n " ,
__func__ , ha - > host_no , drv_state , drv_active ) ;
2012-05-18 12:41:44 +04:00
while ( drv_state ! = ( drv_active & active_mask ) ) {
2010-07-28 14:23:44 +04:00
if ( time_after_eq ( jiffies , reset_timeout ) ) {
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha ,
" %s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x \n " ,
DRIVER_NAME , drv_state , drv_active ) ;
2010-07-28 14:23:44 +04:00
break ;
}
2012-05-18 12:41:44 +04:00
/*
* When reset_owner times out , check which functions
* acked / did not ack
*/
2012-08-22 17:14:24 +04:00
if ( test_bit ( AF_8XXX_RST_OWNER , & ha - > flags ) ) {
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha ,
" %s(%ld): drv_state = 0x%x, drv_active = 0x%x \n " ,
__func__ , ha - > host_no , drv_state ,
drv_active ) ;
}
2012-08-22 15:54:59 +04:00
qla4_82xx_idc_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
msleep ( 1000 ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
2012-08-22 15:54:59 +04:00
drv_state = qla4_82xx_rd_32 ( ha , QLA82XX_CRB_DRV_STATE ) ;
drv_active = qla4_82xx_rd_32 ( ha , QLA82XX_CRB_DRV_ACTIVE ) ;
2010-07-28 14:23:44 +04:00
}
2012-05-18 12:41:44 +04:00
/* Clear RESET OWNER as we are not going to use it any further */
2012-08-22 17:14:24 +04:00
clear_bit ( AF_8XXX_RST_OWNER , & ha - > flags ) ;
2012-05-18 12:41:44 +04:00
2012-08-22 15:54:59 +04:00
dev_state = qla4_82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha , " Device state is 0x%x = %s \n " , dev_state ,
dev_state < MAX_STATES ? qdev_state [ dev_state ] : " Unknown " ) ;
2010-07-28 14:23:44 +04:00
/* Force to DEV_COLD unless someone else is starting a reset */
2012-08-22 17:14:24 +04:00
if ( dev_state ! = QLA8XXX_DEV_INITIALIZING ) {
2010-07-28 14:23:44 +04:00
ql4_printk ( KERN_INFO , ha , " HW State: COLD/RE-INIT \n " ) ;
2012-08-22 17:14:24 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE , QLA8XXX_DEV_COLD ) ;
2012-05-18 12:41:44 +04:00
qla4_8xxx_set_rst_ready ( ha ) ;
2010-07-28 14:23:44 +04:00
}
}
/**
* qla4_8xxx_need_qsnt_handler - Code to start qsnt
* @ ha : pointer to adapter structure
* */
void
qla4_8xxx_need_qsnt_handler ( struct scsi_qla_host * ha )
{
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
qla4_8xxx_set_qsnt_ready ( ha ) ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
}
2012-08-22 15:55:06 +04:00
static void qla4_82xx_set_idc_ver ( struct scsi_qla_host * ha )
{
int idc_ver ;
uint32_t drv_active ;
drv_active = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_ACTIVE ) ;
if ( drv_active = = ( 1 < < ( ha - > func_num * 4 ) ) ) {
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DRV_IDC_VERSION ,
QLA82XX_IDC_VERSION ) ;
ql4_printk ( KERN_INFO , ha ,
" %s: IDC version updated to %d \n " , __func__ ,
QLA82XX_IDC_VERSION ) ;
} else {
idc_ver = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_IDC_VERSION ) ;
if ( QLA82XX_IDC_VERSION ! = idc_ver ) {
ql4_printk ( KERN_INFO , ha ,
" %s: qla4xxx driver IDC version %d is not compatible with IDC version %d of other drivers! \n " ,
__func__ , QLA82XX_IDC_VERSION , idc_ver ) ;
}
}
}
2012-08-22 15:55:08 +04:00
static int qla4_83xx_set_idc_ver ( struct scsi_qla_host * ha )
2012-08-22 15:55:06 +04:00
{
2012-08-22 15:55:08 +04:00
int idc_ver ;
uint32_t drv_active ;
int rval = QLA_SUCCESS ;
drv_active = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_ACTIVE ) ;
if ( drv_active = = ( 1 < < ha - > func_num ) ) {
idc_ver = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_IDC_VERSION ) ;
idc_ver & = ( ~ 0xFF ) ;
idc_ver | = QLA83XX_IDC_VER_MAJ_VALUE ;
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DRV_IDC_VERSION , idc_ver ) ;
ql4_printk ( KERN_INFO , ha ,
" %s: IDC version updated to %d \n " , __func__ ,
2012-09-20 15:35:02 +04:00
idc_ver ) ;
2012-08-22 15:55:08 +04:00
} else {
idc_ver = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_IDC_VERSION ) ;
idc_ver & = 0xFF ;
if ( QLA83XX_IDC_VER_MAJ_VALUE ! = idc_ver ) {
ql4_printk ( KERN_INFO , ha ,
" %s: qla4xxx driver IDC version %d is not compatible with IDC version %d of other drivers! \n " ,
__func__ , QLA83XX_IDC_VER_MAJ_VALUE ,
idc_ver ) ;
rval = QLA_ERROR ;
goto exit_set_idc_ver ;
}
}
/* Update IDC_MINOR_VERSION */
idc_ver = qla4_83xx_rd_reg ( ha , QLA83XX_CRB_IDC_VER_MINOR ) ;
idc_ver & = ~ ( 0x03 < < ( ha - > func_num * 2 ) ) ;
idc_ver | = ( QLA83XX_IDC_VER_MIN_VALUE < < ( ha - > func_num * 2 ) ) ;
qla4_83xx_wr_reg ( ha , QLA83XX_CRB_IDC_VER_MINOR , idc_ver ) ;
exit_set_idc_ver :
return rval ;
}
2012-09-20 15:35:05 +04:00
int qla4_8xxx_update_idc_reg ( struct scsi_qla_host * ha )
2012-08-22 15:55:08 +04:00
{
uint32_t drv_active ;
int rval = QLA_SUCCESS ;
if ( test_bit ( AF_INIT_DONE , & ha - > flags ) )
goto exit_update_idc_reg ;
ha - > isp_ops - > idc_lock ( ha ) ;
qla4_8xxx_set_drv_active ( ha ) ;
/*
* If we are the first driver to load and
* ql4xdontresethba is not set , clear IDC_CTRL BIT0 .
*/
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) ) {
2012-08-22 15:55:08 +04:00
drv_active = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DRV_ACTIVE ) ;
if ( ( drv_active = = ( 1 < < ha - > func_num ) ) & & ! ql4xdontresethba )
qla4_83xx_clear_idc_dontreset ( ha ) ;
}
if ( is_qla8022 ( ha ) ) {
2012-08-22 15:55:06 +04:00
qla4_82xx_set_idc_ver ( ha ) ;
2013-08-16 15:03:02 +04:00
} else if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) ) {
2012-08-22 15:55:08 +04:00
rval = qla4_83xx_set_idc_ver ( ha ) ;
if ( rval = = QLA_ERROR )
qla4_8xxx_clear_drv_active ( ha ) ;
2012-08-22 15:55:06 +04:00
}
2012-08-22 15:55:08 +04:00
ha - > isp_ops - > idc_unlock ( ha ) ;
exit_update_idc_reg :
return rval ;
2010-07-28 14:23:44 +04:00
}
/**
* qla4_8xxx_device_state_handler - Adapter state machine
* @ ha : pointer to host adapter structure .
*
* Note : IDC lock must be UNLOCKED upon entry
* */
int qla4_8xxx_device_state_handler ( struct scsi_qla_host * ha )
{
uint32_t dev_state ;
int rval = QLA_SUCCESS ;
unsigned long dev_init_timeout ;
2012-08-22 15:55:08 +04:00
rval = qla4_8xxx_update_idc_reg ( ha ) ;
if ( rval = = QLA_ERROR )
goto exit_state_handler ;
2010-07-28 14:23:44 +04:00
2012-08-22 15:55:04 +04:00
dev_state = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DEV_STATE ) ;
2012-05-18 12:41:44 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Device state is 0x%x = %s \n " ,
dev_state , dev_state < MAX_STATES ?
qdev_state [ dev_state ] : " Unknown " ) ) ;
2010-07-28 14:23:44 +04:00
/* wait for 30 seconds for device to go ready */
dev_init_timeout = jiffies + ( ha - > nx_dev_init_timeout * HZ ) ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
while ( 1 ) {
if ( time_after_eq ( jiffies , dev_init_timeout ) ) {
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_WARNING , ha ,
" %s: Device Init Failed 0x%x = %s \n " ,
DRIVER_NAME ,
dev_state , dev_state < MAX_STATES ?
qdev_state [ dev_state ] : " Unknown " ) ;
2012-08-22 15:55:04 +04:00
qla4_8xxx_wr_direct ( ha , QLA8XXX_CRB_DEV_STATE ,
QLA8XXX_DEV_FAILED ) ;
2010-07-28 14:23:44 +04:00
}
2012-08-22 15:55:04 +04:00
dev_state = qla4_8xxx_rd_direct ( ha , QLA8XXX_CRB_DEV_STATE ) ;
2012-05-18 12:41:44 +04:00
ql4_printk ( KERN_INFO , ha , " Device state is 0x%x = %s \n " ,
dev_state , dev_state < MAX_STATES ?
qdev_state [ dev_state ] : " Unknown " ) ;
2010-07-28 14:23:44 +04:00
/* NOTE: Make sure idc unlocked upon exit of switch statement */
switch ( dev_state ) {
2012-08-22 17:14:24 +04:00
case QLA8XXX_DEV_READY :
2010-07-28 14:23:44 +04:00
goto exit ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_DEV_COLD :
2010-07-28 14:23:44 +04:00
rval = qla4_8xxx_device_bootstrap ( ha ) ;
goto exit ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_DEV_INITIALIZING :
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
msleep ( 1000 ) ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_DEV_NEED_RESET :
2012-08-22 15:55:08 +04:00
/*
2013-08-16 15:03:02 +04:00
* For ISP8324 and ISP8042 , if NEED_RESET is set by any
* driver , it should be honored , irrespective of
* IDC_CTRL DONTRESET_BIT0
2012-08-22 15:55:08 +04:00
*/
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) ) {
2012-08-22 15:55:08 +04:00
qla4_83xx_need_reset_handler ( ha ) ;
} else if ( is_qla8022 ( ha ) ) {
if ( ! ql4xdontresethba ) {
qla4_82xx_need_reset_handler ( ha ) ;
/* Update timeout value after need
* reset handler */
dev_init_timeout = jiffies +
( ha - > nx_dev_init_timeout * HZ ) ;
} else {
ha - > isp_ops - > idc_unlock ( ha ) ;
msleep ( 1000 ) ;
ha - > isp_ops - > idc_lock ( ha ) ;
}
2010-07-28 14:23:44 +04:00
}
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_DEV_NEED_QUIESCENT :
2010-07-28 14:23:44 +04:00
/* idc locked/unlocked in handler */
qla4_8xxx_need_qsnt_handler ( ha ) ;
2011-12-02 10:42:11 +04:00
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_DEV_QUIESCENT :
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
msleep ( 1000 ) ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
break ;
2012-08-22 17:14:24 +04:00
case QLA8XXX_DEV_FAILED :
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
qla4xxx_dead_adapter_cleanup ( ha ) ;
rval = QLA_ERROR ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
goto exit ;
default :
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
qla4xxx_dead_adapter_cleanup ( ha ) ;
rval = QLA_ERROR ;
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
goto exit ;
}
}
exit :
2012-08-22 15:55:04 +04:00
ha - > isp_ops - > idc_unlock ( ha ) ;
2012-08-22 15:55:08 +04:00
exit_state_handler :
2010-07-28 14:23:44 +04:00
return rval ;
}
int qla4_8xxx_load_risc ( struct scsi_qla_host * ha )
{
int retval ;
2012-01-11 14:44:18 +04:00
/* clear the interrupt */
2013-08-16 15:03:02 +04:00
if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) ) {
2012-08-22 15:55:08 +04:00
writel ( 0 , & ha - > qla4_83xx_reg - > risc_intr ) ;
readl ( & ha - > qla4_83xx_reg - > risc_intr ) ;
} else if ( is_qla8022 ( ha ) ) {
writel ( 0 , & ha - > qla4_82xx_reg - > host_int ) ;
readl ( & ha - > qla4_82xx_reg - > host_int ) ;
}
2012-01-11 14:44:18 +04:00
2010-07-28 14:23:44 +04:00
retval = qla4_8xxx_device_state_handler ( ha ) ;
2013-12-16 15:49:42 +04:00
/* Initialize request and response queues. */
if ( retval = = QLA_SUCCESS )
qla4xxx_init_rings ( ha ) ;
2013-01-21 08:51:01 +04:00
if ( retval = = QLA_SUCCESS & & ! test_bit ( AF_IRQ_ATTACHED , & ha - > flags ) )
2010-07-28 14:23:44 +04:00
retval = qla4xxx_request_irqs ( ha ) ;
2010-10-07 09:47:48 +04:00
2010-07-28 14:23:44 +04:00
return retval ;
}
/*****************************************************************************/
/* Flash Manipulation Routines */
/*****************************************************************************/
# define OPTROM_BURST_SIZE 0x1000
# define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4)
# define FARX_DATA_FLAG BIT_31
# define FARX_ACCESS_FLASH_CONF 0x7FFD0000
# define FARX_ACCESS_FLASH_DATA 0x7FF00000
static inline uint32_t
flash_conf_addr ( struct ql82xx_hw_data * hw , uint32_t faddr )
{
return hw - > flash_conf_off | faddr ;
}
static inline uint32_t
flash_data_addr ( struct ql82xx_hw_data * hw , uint32_t faddr )
{
return hw - > flash_data_off | faddr ;
}
static uint32_t *
2012-08-22 15:54:59 +04:00
qla4_82xx_read_flash_data ( struct scsi_qla_host * ha , uint32_t * dwptr ,
2010-07-28 14:23:44 +04:00
uint32_t faddr , uint32_t length )
{
uint32_t i ;
uint32_t val ;
int loops = 0 ;
2012-08-22 15:54:59 +04:00
while ( ( qla4_82xx_rom_lock ( ha ) ! = 0 ) & & ( loops < 50000 ) ) {
2010-07-28 14:23:44 +04:00
udelay ( 100 ) ;
cond_resched ( ) ;
loops + + ;
}
if ( loops > = 50000 ) {
ql4_printk ( KERN_WARNING , ha , " ROM lock failed \n " ) ;
return dwptr ;
}
/* Dword reads to flash. */
for ( i = 0 ; i < length / 4 ; i + + , faddr + = 4 ) {
2012-08-22 15:54:59 +04:00
if ( qla4_82xx_do_rom_fast_read ( ha , faddr , & val ) ) {
2010-07-28 14:23:44 +04:00
ql4_printk ( KERN_WARNING , ha ,
" Do ROM fast read failed \n " ) ;
goto done_read ;
}
dwptr [ i ] = __constant_cpu_to_le32 ( val ) ;
}
done_read :
2012-08-22 15:54:59 +04:00
qla4_82xx_rom_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
return dwptr ;
}
/**
* Address and length are byte address
* */
static uint8_t *
2012-08-22 15:54:59 +04:00
qla4_82xx_read_optrom_data ( struct scsi_qla_host * ha , uint8_t * buf ,
2010-07-28 14:23:44 +04:00
uint32_t offset , uint32_t length )
{
2012-08-22 15:54:59 +04:00
qla4_82xx_read_flash_data ( ha , ( uint32_t * ) buf , offset , length ) ;
2010-07-28 14:23:44 +04:00
return buf ;
}
static int
qla4_8xxx_find_flt_start ( struct scsi_qla_host * ha , uint32_t * start )
{
const char * loc , * locations [ ] = { " DEF " , " PCI " } ;
/*
* FLT - location structure resides after the last PCI region .
*/
/* Begin with sane defaults. */
loc = locations [ 0 ] ;
* start = FA_FLASH_LAYOUT_ADDR_82 ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " FLTL[%s] = 0x%x. \n " , loc , * start ) ) ;
return QLA_SUCCESS ;
}
static void
qla4_8xxx_get_flt_info ( struct scsi_qla_host * ha , uint32_t flt_addr )
{
const char * loc , * locations [ ] = { " DEF " , " FLT " } ;
uint16_t * wptr ;
uint16_t cnt , chksum ;
2012-08-22 15:55:08 +04:00
uint32_t start , status ;
2010-07-28 14:23:44 +04:00
struct qla_flt_header * flt ;
struct qla_flt_region * region ;
struct ql82xx_hw_data * hw = & ha - > hw ;
hw - > flt_region_flt = flt_addr ;
wptr = ( uint16_t * ) ha - > request_ring ;
flt = ( struct qla_flt_header * ) ha - > request_ring ;
region = ( struct qla_flt_region * ) & flt [ 1 ] ;
2012-08-22 15:55:08 +04:00
if ( is_qla8022 ( ha ) ) {
qla4_82xx_read_optrom_data ( ha , ( uint8_t * ) ha - > request_ring ,
flt_addr < < 2 , OPTROM_BURST_SIZE ) ;
2013-08-16 15:03:02 +04:00
} else if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) ) {
2012-08-22 15:55:08 +04:00
status = qla4_83xx_flash_read_u32 ( ha , flt_addr < < 2 ,
( uint8_t * ) ha - > request_ring ,
0x400 ) ;
if ( status ! = QLA_SUCCESS )
goto no_flash_data ;
}
2010-07-28 14:23:44 +04:00
if ( * wptr = = __constant_cpu_to_le16 ( 0xffff ) )
goto no_flash_data ;
if ( flt - > version ! = __constant_cpu_to_le16 ( 1 ) ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Unsupported FLT detected: "
" version=0x%x length=0x%x checksum=0x%x. \n " ,
le16_to_cpu ( flt - > version ) , le16_to_cpu ( flt - > length ) ,
le16_to_cpu ( flt - > checksum ) ) ) ;
goto no_flash_data ;
}
cnt = ( sizeof ( struct qla_flt_header ) + le16_to_cpu ( flt - > length ) ) > > 1 ;
for ( chksum = 0 ; cnt ; cnt - - )
chksum + = le16_to_cpu ( * wptr + + ) ;
if ( chksum ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Inconsistent FLT detected: "
" version=0x%x length=0x%x checksum=0x%x. \n " ,
le16_to_cpu ( flt - > version ) , le16_to_cpu ( flt - > length ) ,
chksum ) ) ;
goto no_flash_data ;
}
loc = locations [ 1 ] ;
cnt = le16_to_cpu ( flt - > length ) / sizeof ( struct qla_flt_region ) ;
for ( ; cnt ; cnt - - , region + + ) {
/* Store addresses as DWORD offsets. */
start = le32_to_cpu ( region - > start ) > > 2 ;
DEBUG3 ( ql4_printk ( KERN_DEBUG , ha , " FLT[%02x]: start=0x%x "
" end=0x%x size=0x%x. \n " , le32_to_cpu ( region - > code ) , start ,
le32_to_cpu ( region - > end ) > > 2 , le32_to_cpu ( region - > size ) ) ) ;
switch ( le32_to_cpu ( region - > code ) & 0xff ) {
case FLT_REG_FDT :
hw - > flt_region_fdt = start ;
break ;
case FLT_REG_BOOT_CODE_82 :
hw - > flt_region_boot = start ;
break ;
case FLT_REG_FW_82 :
2011-10-08 03:55:39 +04:00
case FLT_REG_FW_82_1 :
2010-07-28 14:23:44 +04:00
hw - > flt_region_fw = start ;
break ;
case FLT_REG_BOOTLOAD_82 :
hw - > flt_region_bootload = start ;
break ;
2011-07-25 22:48:55 +04:00
case FLT_REG_ISCSI_PARAM :
hw - > flt_iscsi_param = start ;
break ;
2011-10-08 03:55:42 +04:00
case FLT_REG_ISCSI_CHAP :
hw - > flt_region_chap = start ;
hw - > flt_chap_size = le32_to_cpu ( region - > size ) ;
break ;
2013-03-22 15:41:31 +04:00
case FLT_REG_ISCSI_DDB :
hw - > flt_region_ddb = start ;
hw - > flt_ddb_size = le32_to_cpu ( region - > size ) ;
break ;
2010-07-28 14:23:44 +04:00
}
}
goto done ;
no_flash_data :
/* Use hardcoded defaults. */
loc = locations [ 0 ] ;
hw - > flt_region_fdt = FA_FLASH_DESCR_ADDR_82 ;
hw - > flt_region_boot = FA_BOOT_CODE_ADDR_82 ;
hw - > flt_region_bootload = FA_BOOT_LOAD_ADDR_82 ;
hw - > flt_region_fw = FA_RISC_CODE_ADDR_82 ;
2013-03-22 15:08:32 +04:00
hw - > flt_region_chap = FA_FLASH_ISCSI_CHAP > > 2 ;
2011-10-08 03:55:42 +04:00
hw - > flt_chap_size = FA_FLASH_CHAP_SIZE ;
2013-03-22 15:41:31 +04:00
hw - > flt_region_ddb = FA_FLASH_ISCSI_DDB > > 2 ;
hw - > flt_ddb_size = FA_FLASH_DDB_SIZE ;
2011-10-08 03:55:42 +04:00
2010-07-28 14:23:44 +04:00
done :
2013-03-22 15:08:32 +04:00
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
2013-03-22 15:41:31 +04:00
" FLT[%s]: flt=0x%x fdt=0x%x boot=0x%x bootload=0x%x fw=0x%x chap=0x%x chap_size=0x%x ddb=0x%x ddb_size=0x%x \n " ,
2013-03-22 15:08:32 +04:00
loc , hw - > flt_region_flt , hw - > flt_region_fdt ,
hw - > flt_region_boot , hw - > flt_region_bootload ,
2013-03-22 15:41:31 +04:00
hw - > flt_region_fw , hw - > flt_region_chap ,
hw - > flt_chap_size , hw - > flt_region_ddb ,
hw - > flt_ddb_size ) ) ;
2010-07-28 14:23:44 +04:00
}
static void
2012-08-22 15:54:59 +04:00
qla4_82xx_get_fdt_info ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
# define FLASH_BLK_SIZE_4K 0x1000
# define FLASH_BLK_SIZE_32K 0x8000
# define FLASH_BLK_SIZE_64K 0x10000
const char * loc , * locations [ ] = { " MID " , " FDT " } ;
uint16_t cnt , chksum ;
uint16_t * wptr ;
struct qla_fdt_layout * fdt ;
2010-08-09 16:14:07 +04:00
uint16_t mid = 0 ;
uint16_t fid = 0 ;
2010-07-28 14:23:44 +04:00
struct ql82xx_hw_data * hw = & ha - > hw ;
hw - > flash_conf_off = FARX_ACCESS_FLASH_CONF ;
hw - > flash_data_off = FARX_ACCESS_FLASH_DATA ;
wptr = ( uint16_t * ) ha - > request_ring ;
fdt = ( struct qla_fdt_layout * ) ha - > request_ring ;
2012-08-22 15:54:59 +04:00
qla4_82xx_read_optrom_data ( ha , ( uint8_t * ) ha - > request_ring ,
2010-07-28 14:23:44 +04:00
hw - > flt_region_fdt < < 2 , OPTROM_BURST_SIZE ) ;
if ( * wptr = = __constant_cpu_to_le16 ( 0xffff ) )
goto no_flash_data ;
if ( fdt - > sig [ 0 ] ! = ' Q ' | | fdt - > sig [ 1 ] ! = ' L ' | | fdt - > sig [ 2 ] ! = ' I ' | |
fdt - > sig [ 3 ] ! = ' D ' )
goto no_flash_data ;
for ( cnt = 0 , chksum = 0 ; cnt < sizeof ( struct qla_fdt_layout ) > > 1 ;
cnt + + )
chksum + = le16_to_cpu ( * wptr + + ) ;
if ( chksum ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " Inconsistent FDT detected: "
" checksum=0x%x id=%c version=0x%x. \n " , chksum , fdt - > sig [ 0 ] ,
le16_to_cpu ( fdt - > version ) ) ) ;
goto no_flash_data ;
}
loc = locations [ 1 ] ;
mid = le16_to_cpu ( fdt - > man_id ) ;
fid = le16_to_cpu ( fdt - > id ) ;
hw - > fdt_wrt_disable = fdt - > wrt_disable_bits ;
hw - > fdt_erase_cmd = flash_conf_addr ( hw , 0x0300 | fdt - > erase_cmd ) ;
hw - > fdt_block_size = le32_to_cpu ( fdt - > block_size ) ;
if ( fdt - > unprotect_sec_cmd ) {
hw - > fdt_unprotect_sec_cmd = flash_conf_addr ( hw , 0x0300 |
fdt - > unprotect_sec_cmd ) ;
hw - > fdt_protect_sec_cmd = fdt - > protect_sec_cmd ?
flash_conf_addr ( hw , 0x0300 | fdt - > protect_sec_cmd ) :
flash_conf_addr ( hw , 0x0336 ) ;
}
goto done ;
no_flash_data :
loc = locations [ 0 ] ;
hw - > fdt_block_size = FLASH_BLK_SIZE_64K ;
done :
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " FDT[%s]: (0x%x/0x%x) erase=0x%x "
" pro=%x upro=%x wrtd=0x%x blk=0x%x. \n " , loc , mid , fid ,
hw - > fdt_erase_cmd , hw - > fdt_protect_sec_cmd ,
hw - > fdt_unprotect_sec_cmd , hw - > fdt_wrt_disable ,
hw - > fdt_block_size ) ) ;
}
static void
2012-08-22 15:54:59 +04:00
qla4_82xx_get_idc_param ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
# define QLA82XX_IDC_PARAM_ADDR 0x003e885c
uint32_t * wptr ;
if ( ! is_qla8022 ( ha ) )
return ;
wptr = ( uint32_t * ) ha - > request_ring ;
2012-08-22 15:54:59 +04:00
qla4_82xx_read_optrom_data ( ha , ( uint8_t * ) ha - > request_ring ,
2010-07-28 14:23:44 +04:00
QLA82XX_IDC_PARAM_ADDR , 8 ) ;
if ( * wptr = = __constant_cpu_to_le32 ( 0xffffffff ) ) {
ha - > nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT ;
ha - > nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT ;
} else {
ha - > nx_dev_init_timeout = le32_to_cpu ( * wptr + + ) ;
ha - > nx_reset_timeout = le32_to_cpu ( * wptr ) ;
}
DEBUG2 ( ql4_printk ( KERN_DEBUG , ha ,
" ha->nx_dev_init_timeout = %d \n " , ha - > nx_dev_init_timeout ) ) ;
DEBUG2 ( ql4_printk ( KERN_DEBUG , ha ,
" ha->nx_reset_timeout = %d \n " , ha - > nx_reset_timeout ) ) ;
return ;
}
2012-08-22 15:55:04 +04:00
void qla4_82xx_queue_mbox_cmd ( struct scsi_qla_host * ha , uint32_t * mbx_cmd ,
int in_count )
{
int i ;
/* Load all mailbox registers, except mailbox 0. */
for ( i = 1 ; i < in_count ; i + + )
writel ( mbx_cmd [ i ] , & ha - > qla4_82xx_reg - > mailbox_in [ i ] ) ;
/* Wakeup firmware */
writel ( mbx_cmd [ 0 ] , & ha - > qla4_82xx_reg - > mailbox_in [ 0 ] ) ;
readl ( & ha - > qla4_82xx_reg - > mailbox_in [ 0 ] ) ;
writel ( HINT_MBX_INT_PENDING , & ha - > qla4_82xx_reg - > hint ) ;
readl ( & ha - > qla4_82xx_reg - > hint ) ;
}
void qla4_82xx_process_mbox_intr ( struct scsi_qla_host * ha , int out_count )
{
int intr_status ;
intr_status = readl ( & ha - > qla4_82xx_reg - > host_int ) ;
if ( intr_status & ISRX_82XX_RISC_INT ) {
ha - > mbox_status_count = out_count ;
intr_status = readl ( & ha - > qla4_82xx_reg - > host_status ) ;
ha - > isp_ops - > interrupt_service_routine ( ha , intr_status ) ;
if ( test_bit ( AF_INTERRUPTS_ON , & ha - > flags ) & &
test_bit ( AF_INTx_ENABLED , & ha - > flags ) )
qla4_82xx_wr_32 ( ha , ha - > nx_legacy_intr . tgt_mask_reg ,
0xfbff ) ;
}
2010-07-28 14:23:44 +04:00
}
int
qla4_8xxx_get_flash_info ( struct scsi_qla_host * ha )
{
int ret ;
uint32_t flt_addr ;
ret = qla4_8xxx_find_flt_start ( ha , & flt_addr ) ;
if ( ret ! = QLA_SUCCESS )
return ret ;
qla4_8xxx_get_flt_info ( ha , flt_addr ) ;
2012-08-22 15:55:08 +04:00
if ( is_qla8022 ( ha ) ) {
qla4_82xx_get_fdt_info ( ha ) ;
qla4_82xx_get_idc_param ( ha ) ;
2013-08-16 15:03:02 +04:00
} else if ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) ) {
2012-08-22 15:55:08 +04:00
qla4_83xx_get_idc_param ( ha ) ;
}
2010-07-28 14:23:44 +04:00
return QLA_SUCCESS ;
}
/**
* qla4_8xxx_stop_firmware - stops firmware on specified adapter instance
* @ ha : pointer to host adapter structure .
*
* Remarks :
* For iSCSI , throws away all I / O and AENs into bit bucket , so they will
* not be available after successful return . Driver must cleanup potential
* outstanding I / O ' s after calling this funcion .
* */
int
qla4_8xxx_stop_firmware ( struct scsi_qla_host * ha )
{
int status ;
uint32_t mbox_cmd [ MBOX_REG_COUNT ] ;
uint32_t mbox_sts [ MBOX_REG_COUNT ] ;
memset ( & mbox_cmd , 0 , sizeof ( mbox_cmd ) ) ;
memset ( & mbox_sts , 0 , sizeof ( mbox_sts ) ) ;
mbox_cmd [ 0 ] = MBOX_CMD_STOP_FW ;
status = qla4xxx_mailbox_command ( ha , MBOX_REG_COUNT , 1 ,
& mbox_cmd [ 0 ] , & mbox_sts [ 0 ] ) ;
DEBUG2 ( printk ( " scsi%ld: %s: status = %d \n " , ha - > host_no ,
__func__ , status ) ) ;
return status ;
}
/**
2012-08-22 15:54:59 +04:00
* qla4_82xx_isp_reset - Resets ISP and aborts all outstanding commands .
2010-07-28 14:23:44 +04:00
* @ ha : pointer to host adapter structure .
* */
int
2012-08-22 15:54:59 +04:00
qla4_82xx_isp_reset ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
int rval ;
uint32_t dev_state ;
2012-08-22 15:54:59 +04:00
qla4_82xx_idc_lock ( ha ) ;
dev_state = qla4_82xx_rd_32 ( ha , QLA82XX_CRB_DEV_STATE ) ;
2010-07-28 14:23:44 +04:00
2012-08-22 17:14:24 +04:00
if ( dev_state = = QLA8XXX_DEV_READY ) {
2010-07-28 14:23:44 +04:00
ql4_printk ( KERN_INFO , ha , " HW State: NEED RESET \n " ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , QLA82XX_CRB_DEV_STATE ,
2012-08-22 17:14:24 +04:00
QLA8XXX_DEV_NEED_RESET ) ;
set_bit ( AF_8XXX_RST_OWNER , & ha - > flags ) ;
2010-07-28 14:23:44 +04:00
} else
ql4_printk ( KERN_INFO , ha , " HW State: DEVICE INITIALIZING \n " ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_idc_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
rval = qla4_8xxx_device_state_handler ( ha ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_idc_lock ( ha ) ;
2010-07-28 14:23:44 +04:00
qla4_8xxx_clear_rst_ready ( ha ) ;
2012-08-22 15:54:59 +04:00
qla4_82xx_idc_unlock ( ha ) ;
2010-07-28 14:23:44 +04:00
2012-05-18 12:41:44 +04:00
if ( rval = = QLA_SUCCESS ) {
2012-08-22 15:54:59 +04:00
ql4_printk ( KERN_INFO , ha , " Clearing AF_RECOVERY in qla4_82xx_isp_reset \n " ) ;
2010-07-30 12:58:07 +04:00
clear_bit ( AF_FW_RECOVERY , & ha - > flags ) ;
2012-05-18 12:41:44 +04:00
}
2010-07-30 12:58:07 +04:00
2010-07-28 14:23:44 +04:00
return rval ;
}
/**
* qla4_8xxx_get_sys_info - get adapter MAC address ( es ) and serial number
* @ ha : pointer to host adapter structure .
*
* */
int qla4_8xxx_get_sys_info ( struct scsi_qla_host * ha )
{
uint32_t mbox_cmd [ MBOX_REG_COUNT ] ;
uint32_t mbox_sts [ MBOX_REG_COUNT ] ;
struct mbx_sys_info * sys_info ;
dma_addr_t sys_info_dma ;
int status = QLA_ERROR ;
sys_info = dma_alloc_coherent ( & ha - > pdev - > dev , sizeof ( * sys_info ) ,
& sys_info_dma , GFP_KERNEL ) ;
if ( sys_info = = NULL ) {
DEBUG2 ( printk ( " scsi%ld: %s: Unable to allocate dma buffer. \n " ,
ha - > host_no , __func__ ) ) ;
return status ;
}
memset ( sys_info , 0 , sizeof ( * sys_info ) ) ;
memset ( & mbox_cmd , 0 , sizeof ( mbox_cmd ) ) ;
memset ( & mbox_sts , 0 , sizeof ( mbox_sts ) ) ;
mbox_cmd [ 0 ] = MBOX_CMD_GET_SYS_INFO ;
mbox_cmd [ 1 ] = LSDW ( sys_info_dma ) ;
mbox_cmd [ 2 ] = MSDW ( sys_info_dma ) ;
mbox_cmd [ 4 ] = sizeof ( * sys_info ) ;
if ( qla4xxx_mailbox_command ( ha , MBOX_REG_COUNT , 6 , & mbox_cmd [ 0 ] ,
& mbox_sts [ 0 ] ) ! = QLA_SUCCESS ) {
DEBUG2 ( printk ( " scsi%ld: %s: GET_SYS_INFO failed \n " ,
ha - > host_no , __func__ ) ) ;
goto exit_validate_mac82 ;
}
2010-07-30 12:57:45 +04:00
/* Make sure we receive the minimum required data to cache internally */
2013-08-16 15:03:02 +04:00
if ( ( ( is_qla8032 ( ha ) | | is_qla8042 ( ha ) ) ? mbox_sts [ 3 ] : mbox_sts [ 4 ] ) <
2012-12-29 11:24:53 +04:00
offsetof ( struct mbx_sys_info , reserved ) ) {
2010-07-28 14:23:44 +04:00
DEBUG2 ( printk ( " scsi%ld: %s: GET_SYS_INFO data receive "
" error (%x) \n " , ha - > host_no , __func__ , mbox_sts [ 4 ] ) ) ;
goto exit_validate_mac82 ;
}
/* Save M.A.C. address & serial_number */
2011-07-25 22:48:55 +04:00
ha - > port_num = sys_info - > port_num ;
2010-07-28 14:23:44 +04:00
memcpy ( ha - > my_mac , & sys_info - > mac_addr [ 0 ] ,
min ( sizeof ( ha - > my_mac ) , sizeof ( sys_info - > mac_addr ) ) ) ;
memcpy ( ha - > serial_number , & sys_info - > serial_number ,
min ( sizeof ( ha - > serial_number ) , sizeof ( sys_info - > serial_number ) ) ) ;
2011-08-01 14:26:17 +04:00
memcpy ( ha - > model_name , & sys_info - > board_id_str ,
min ( sizeof ( ha - > model_name ) , sizeof ( sys_info - > board_id_str ) ) ) ;
ha - > phy_port_cnt = sys_info - > phys_port_cnt ;
ha - > phy_port_num = sys_info - > port_num ;
ha - > iscsi_pci_func_cnt = sys_info - > iscsi_pci_func_cnt ;
2010-07-28 14:23:44 +04:00
DEBUG2 ( printk ( " scsi%ld: %s: "
" mac %02x:%02x:%02x:%02x:%02x:%02x "
" serial %s \n " , ha - > host_no , __func__ ,
ha - > my_mac [ 0 ] , ha - > my_mac [ 1 ] , ha - > my_mac [ 2 ] ,
ha - > my_mac [ 3 ] , ha - > my_mac [ 4 ] , ha - > my_mac [ 5 ] ,
ha - > serial_number ) ) ;
status = QLA_SUCCESS ;
exit_validate_mac82 :
dma_free_coherent ( & ha - > pdev - > dev , sizeof ( * sys_info ) , sys_info ,
sys_info_dma ) ;
return status ;
}
/* Interrupt handling helpers. */
2012-11-23 15:58:38 +04:00
int qla4_8xxx_intr_enable ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
uint32_t mbox_cmd [ MBOX_REG_COUNT ] ;
uint32_t mbox_sts [ MBOX_REG_COUNT ] ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s \n " , __func__ ) ) ;
memset ( & mbox_cmd , 0 , sizeof ( mbox_cmd ) ) ;
memset ( & mbox_sts , 0 , sizeof ( mbox_sts ) ) ;
mbox_cmd [ 0 ] = MBOX_CMD_ENABLE_INTRS ;
mbox_cmd [ 1 ] = INTR_ENABLE ;
if ( qla4xxx_mailbox_command ( ha , MBOX_REG_COUNT , 1 , & mbox_cmd [ 0 ] ,
& mbox_sts [ 0 ] ) ! = QLA_SUCCESS ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: MBOX_CMD_ENABLE_INTRS failed (0x%04x) \n " ,
__func__ , mbox_sts [ 0 ] ) ) ;
return QLA_ERROR ;
}
return QLA_SUCCESS ;
}
2012-11-23 15:58:38 +04:00
int qla4_8xxx_intr_disable ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
uint32_t mbox_cmd [ MBOX_REG_COUNT ] ;
uint32_t mbox_sts [ MBOX_REG_COUNT ] ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s \n " , __func__ ) ) ;
memset ( & mbox_cmd , 0 , sizeof ( mbox_cmd ) ) ;
memset ( & mbox_sts , 0 , sizeof ( mbox_sts ) ) ;
mbox_cmd [ 0 ] = MBOX_CMD_ENABLE_INTRS ;
mbox_cmd [ 1 ] = INTR_DISABLE ;
if ( qla4xxx_mailbox_command ( ha , MBOX_REG_COUNT , 1 , & mbox_cmd [ 0 ] ,
& mbox_sts [ 0 ] ) ! = QLA_SUCCESS ) {
DEBUG2 ( ql4_printk ( KERN_INFO , ha ,
" %s: MBOX_CMD_ENABLE_INTRS failed (0x%04x) \n " ,
__func__ , mbox_sts [ 0 ] ) ) ;
return QLA_ERROR ;
}
return QLA_SUCCESS ;
}
void
2012-08-22 15:54:59 +04:00
qla4_82xx_enable_intrs ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
2012-11-23 15:58:38 +04:00
qla4_8xxx_intr_enable ( ha ) ;
2010-07-28 14:23:44 +04:00
spin_lock_irq ( & ha - > hardware_lock ) ;
/* BIT 10 - reset */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , ha - > nx_legacy_intr . tgt_mask_reg , 0xfbff ) ;
2010-07-28 14:23:44 +04:00
spin_unlock_irq ( & ha - > hardware_lock ) ;
set_bit ( AF_INTERRUPTS_ON , & ha - > flags ) ;
}
void
2012-08-22 15:54:59 +04:00
qla4_82xx_disable_intrs ( struct scsi_qla_host * ha )
2010-07-28 14:23:44 +04:00
{
2011-03-23 18:07:33 +03:00
if ( test_and_clear_bit ( AF_INTERRUPTS_ON , & ha - > flags ) )
2012-11-23 15:58:38 +04:00
qla4_8xxx_intr_disable ( ha ) ;
2010-07-28 14:23:44 +04:00
spin_lock_irq ( & ha - > hardware_lock ) ;
/* BIT 10 - set */
2012-08-22 15:54:59 +04:00
qla4_82xx_wr_32 ( ha , ha - > nx_legacy_intr . tgt_mask_reg , 0x0400 ) ;
2010-07-28 14:23:44 +04:00
spin_unlock_irq ( & ha - > hardware_lock ) ;
}
struct ql4_init_msix_entry {
uint16_t entry ;
uint16_t index ;
const char * name ;
irq_handler_t handler ;
} ;
static struct ql4_init_msix_entry qla4_8xxx_msix_entries [ QLA_MSIX_ENTRIES ] = {
{ QLA_MSIX_DEFAULT , QLA_MIDX_DEFAULT ,
" qla4xxx (default) " ,
( irq_handler_t ) qla4_8xxx_default_intr_handler } ,
{ QLA_MSIX_RSP_Q , QLA_MIDX_RSP_Q ,
" qla4xxx (rsp_q) " , ( irq_handler_t ) qla4_8xxx_msix_rsp_q } ,
} ;
void
qla4_8xxx_disable_msix ( struct scsi_qla_host * ha )
{
int i ;
struct ql4_msix_entry * qentry ;
for ( i = 0 ; i < QLA_MSIX_ENTRIES ; i + + ) {
qentry = & ha - > msix_entries [ qla4_8xxx_msix_entries [ i ] . index ] ;
if ( qentry - > have_irq ) {
free_irq ( qentry - > msix_vector , ha ) ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s: %s \n " ,
__func__ , qla4_8xxx_msix_entries [ i ] . name ) ) ;
}
}
pci_disable_msix ( ha - > pdev ) ;
clear_bit ( AF_MSIX_ENABLED , & ha - > flags ) ;
}
int
qla4_8xxx_enable_msix ( struct scsi_qla_host * ha )
{
int i , ret ;
struct msix_entry entries [ QLA_MSIX_ENTRIES ] ;
struct ql4_msix_entry * qentry ;
for ( i = 0 ; i < QLA_MSIX_ENTRIES ; i + + )
entries [ i ] . entry = qla4_8xxx_msix_entries [ i ] . entry ;
2014-07-16 22:05:26 +04:00
ret = pci_enable_msix_exact ( ha - > pdev , entries , ARRAY_SIZE ( entries ) ) ;
2010-07-28 14:23:44 +04:00
if ( ret ) {
ql4_printk ( KERN_WARNING , ha ,
" MSI-X: Failed to enable support -- %d/%d \n " ,
QLA_MSIX_ENTRIES , ret ) ;
goto msix_out ;
}
set_bit ( AF_MSIX_ENABLED , & ha - > flags ) ;
for ( i = 0 ; i < QLA_MSIX_ENTRIES ; i + + ) {
qentry = & ha - > msix_entries [ qla4_8xxx_msix_entries [ i ] . index ] ;
qentry - > msix_vector = entries [ i ] . vector ;
qentry - > msix_entry = entries [ i ] . entry ;
qentry - > have_irq = 0 ;
ret = request_irq ( qentry - > msix_vector ,
qla4_8xxx_msix_entries [ i ] . handler , 0 ,
qla4_8xxx_msix_entries [ i ] . name , ha ) ;
if ( ret ) {
ql4_printk ( KERN_WARNING , ha ,
" MSI-X: Unable to register handler -- %x/%d. \n " ,
qla4_8xxx_msix_entries [ i ] . index , ret ) ;
qla4_8xxx_disable_msix ( ha ) ;
goto msix_out ;
}
qentry - > have_irq = 1 ;
DEBUG2 ( ql4_printk ( KERN_INFO , ha , " %s: %s \n " ,
__func__ , qla4_8xxx_msix_entries [ i ] . name ) ) ;
}
msix_out :
return ret ;
}
2013-12-16 15:49:31 +04:00
int qla4_8xxx_check_init_adapter_retry ( struct scsi_qla_host * ha )
{
int status = QLA_SUCCESS ;
/* Dont retry adapter initialization if IRQ allocation failed */
if ( ! test_bit ( AF_IRQ_ATTACHED , & ha - > flags ) ) {
ql4_printk ( KERN_WARNING , ha , " %s: Skipping retry of adapter initialization as IRQs are not attached \n " ,
__func__ ) ;
status = QLA_ERROR ;
goto exit_init_adapter_failure ;
}
/* Since interrupts are registered in start_firmware for
* 8 xxx , release them here if initialize_adapter fails
* and retry adapter initialization */
qla4xxx_free_irqs ( ha ) ;
exit_init_adapter_failure :
return status ;
}