2014-02-26 13:15:06 +04:00
/*
* QLogic Fibre Channel HBA Driver
2014-04-12 00:54:24 +04:00
* Copyright ( c ) 2003 - 2014 QLogic Corporation
2014-02-26 13:15:06 +04:00
*
* See LICENSE . qla2xxx for copyright and licensing details .
*/
# include "qla_def.h"
# include "qla_tmpl.h"
/* note default template is in big endian */
static const uint32_t ql27xx_fwdt_default_template [ ] = {
0x63000000 , 0xa4000000 , 0x7c050000 , 0x00000000 ,
0x30000000 , 0x01000000 , 0x00000000 , 0xc0406eb4 ,
0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x04010000 , 0x14000000 , 0x00000000 ,
0x02000000 , 0x44000000 , 0x09010000 , 0x10000000 ,
0x00000000 , 0x02000000 , 0x01010000 , 0x1c000000 ,
0x00000000 , 0x02000000 , 0x00600000 , 0x00000000 ,
0xc0000000 , 0x01010000 , 0x1c000000 , 0x00000000 ,
0x02000000 , 0x00600000 , 0x00000000 , 0xcc000000 ,
0x01010000 , 0x1c000000 , 0x00000000 , 0x02000000 ,
0x10600000 , 0x00000000 , 0xd4000000 , 0x01010000 ,
0x1c000000 , 0x00000000 , 0x02000000 , 0x700f0000 ,
0x00000060 , 0xf0000000 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x00700000 , 0x041000c0 ,
0x00010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x10700000 , 0x041000c0 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x40700000 , 0x041000c0 ,
0x01010000 , 0x1c000000 , 0x00000000 , 0x02000000 ,
0x007c0000 , 0x01000000 , 0xc0000000 , 0x00010000 ,
0x18000000 , 0x00000000 , 0x02000000 , 0x007c0000 ,
0x040300c4 , 0x00010000 , 0x18000000 , 0x00000000 ,
0x02000000 , 0x007c0000 , 0x040100c0 , 0x01010000 ,
0x1c000000 , 0x00000000 , 0x02000000 , 0x007c0000 ,
0x00000000 , 0xc0000000 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x007c0000 , 0x04200000 ,
0x0b010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x0c000000 , 0x00000000 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000000b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000010b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000020b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000030b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000040b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000050b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000060b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000070b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000080b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x000090b0 , 0x02010000 , 0x20000000 ,
0x00000000 , 0x02000000 , 0x700f0000 , 0x040100fc ,
0xf0000000 , 0x0000a0b0 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x0a000000 , 0x040100c0 ,
0x00010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x0a000000 , 0x04200080 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x00be0000 , 0x041000c0 ,
0x00010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x10be0000 , 0x041000c0 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x20be0000 , 0x041000c0 ,
0x00010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x30be0000 , 0x041000c0 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x00b00000 , 0x041000c0 ,
0x00010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x10b00000 , 0x041000c0 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x20b00000 , 0x041000c0 ,
0x00010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x30b00000 , 0x041000c0 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x00300000 , 0x041000c0 ,
0x00010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x10300000 , 0x041000c0 , 0x00010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x20300000 , 0x041000c0 ,
0x00010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x30300000 , 0x041000c0 , 0x0a010000 , 0x10000000 ,
0x00000000 , 0x02000000 , 0x06010000 , 0x1c000000 ,
0x00000000 , 0x02000000 , 0x01000000 , 0x00000200 ,
0xff230200 , 0x06010000 , 0x1c000000 , 0x00000000 ,
0x02000000 , 0x02000000 , 0x00001000 , 0x00000000 ,
0x07010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x00000000 , 0x01000000 , 0x07010000 , 0x18000000 ,
0x00000000 , 0x02000000 , 0x00000000 , 0x02000000 ,
0x07010000 , 0x18000000 , 0x00000000 , 0x02000000 ,
0x00000000 , 0x03000000 , 0x0d010000 , 0x14000000 ,
0x00000000 , 0x02000000 , 0x00000000 , 0xff000000 ,
0x10000000 , 0x00000000 , 0x00000080 ,
} ;
static inline void __iomem *
qla27xx_isp_reg ( struct scsi_qla_host * vha )
{
return & vha - > hw - > iobase - > isp24 ;
}
static inline void
qla27xx_insert16 ( uint16_t value , void * buf , ulong * len )
{
if ( buf ) {
buf + = * len ;
* ( __le16 * ) buf = cpu_to_le16 ( value ) ;
}
* len + = sizeof ( value ) ;
}
static inline void
qla27xx_insert32 ( uint32_t value , void * buf , ulong * len )
{
if ( buf ) {
buf + = * len ;
* ( __le32 * ) buf = cpu_to_le32 ( value ) ;
}
* len + = sizeof ( value ) ;
}
static inline void
qla27xx_insertbuf ( void * mem , ulong size , void * buf , ulong * len )
{
2014-09-25 13:16:35 +04:00
if ( buf & & mem & & size ) {
2014-02-26 13:15:06 +04:00
buf + = * len ;
2014-09-25 13:16:35 +04:00
memcpy ( buf , mem , size ) ;
2014-02-26 13:15:06 +04:00
}
* len + = size ;
}
static inline void
2015-07-09 17:24:50 +03:00
qla27xx_read8 ( void __iomem * window , void * buf , ulong * len )
2014-02-26 13:15:06 +04:00
{
uint8_t value = ~ 0 ;
if ( buf ) {
2015-07-09 17:24:50 +03:00
value = RD_REG_BYTE ( window ) ;
2014-02-26 13:15:06 +04:00
}
qla27xx_insert32 ( value , buf , len ) ;
}
static inline void
2015-07-09 17:24:50 +03:00
qla27xx_read16 ( void __iomem * window , void * buf , ulong * len )
2014-02-26 13:15:06 +04:00
{
uint16_t value = ~ 0 ;
if ( buf ) {
2015-07-09 17:24:50 +03:00
value = RD_REG_WORD ( window ) ;
2014-02-26 13:15:06 +04:00
}
qla27xx_insert32 ( value , buf , len ) ;
}
static inline void
2015-07-09 17:24:50 +03:00
qla27xx_read32 ( void __iomem * window , void * buf , ulong * len )
2014-02-26 13:15:06 +04:00
{
uint32_t value = ~ 0 ;
if ( buf ) {
2015-07-09 17:24:50 +03:00
value = RD_REG_DWORD ( window ) ;
2014-02-26 13:15:06 +04:00
}
qla27xx_insert32 ( value , buf , len ) ;
}
2015-07-09 17:24:50 +03:00
static inline void ( * qla27xx_read_vector ( uint width ) ) ( void __iomem * , void * , ulong * )
2014-02-26 13:15:06 +04:00
{
return
( width = = 1 ) ? qla27xx_read8 :
( width = = 2 ) ? qla27xx_read16 :
qla27xx_read32 ;
}
static inline void
qla27xx_read_reg ( __iomem struct device_reg_24xx * reg ,
uint offset , void * buf , ulong * len )
{
2015-07-09 17:24:50 +03:00
void __iomem * window = ( void __iomem * ) reg + offset ;
2014-02-26 13:15:06 +04:00
qla27xx_read32 ( window , buf , len ) ;
}
static inline void
qla27xx_write_reg ( __iomem struct device_reg_24xx * reg ,
uint offset , uint32_t data , void * buf )
{
2015-04-09 21:59:56 +03:00
__iomem void * window = ( void __iomem * ) reg + offset ;
2014-02-26 13:15:06 +04:00
if ( buf ) {
WRT_REG_DWORD ( window , data ) ;
}
}
static inline void
qla27xx_read_window ( __iomem struct device_reg_24xx * reg ,
2014-04-12 00:54:36 +04:00
uint32_t addr , uint offset , uint count , uint width , void * buf ,
2014-02-26 13:15:06 +04:00
ulong * len )
{
2015-07-09 17:24:50 +03:00
void __iomem * window = ( void __iomem * ) reg + offset ;
void ( * readn ) ( void __iomem * , void * , ulong * ) = qla27xx_read_vector ( width ) ;
2014-02-26 13:15:06 +04:00
2014-04-12 00:54:36 +04:00
qla27xx_write_reg ( reg , IOBASE_ADDR , addr , buf ) ;
2014-02-26 13:15:06 +04:00
while ( count - - ) {
2014-04-12 00:54:36 +04:00
qla27xx_insert32 ( addr , buf , len ) ;
2014-02-26 13:15:06 +04:00
readn ( window , buf , len ) ;
window + = width ;
2014-04-12 00:54:36 +04:00
addr + + ;
2014-02-26 13:15:06 +04:00
}
}
static inline void
qla27xx_skip_entry ( struct qla27xx_fwdt_entry * ent , void * buf )
{
if ( buf )
ent - > hdr . driver_flags | = DRIVER_FLAG_SKIP_ENTRY ;
}
static int
qla27xx_fwdt_entry_t0 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ql_dbg ( ql_dbg_misc , vha , 0xd100 ,
" %s: nop [%lx] \n " , __func__ , * len ) ;
qla27xx_skip_entry ( ent , buf ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t255 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ql_dbg ( ql_dbg_misc , vha , 0xd1ff ,
" %s: end [%lx] \n " , __func__ , * len ) ;
qla27xx_skip_entry ( ent , buf ) ;
/* terminate */
return true ;
}
static int
qla27xx_fwdt_entry_t256 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ql_dbg ( ql_dbg_misc , vha , 0xd200 ,
" %s: rdio t1 [%lx] \n " , __func__ , * len ) ;
qla27xx_read_window ( reg , ent - > t256 . base_addr , ent - > t256 . pci_offset ,
ent - > t256 . reg_count , ent - > t256 . reg_width , buf , len ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t257 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ql_dbg ( ql_dbg_misc , vha , 0xd201 ,
" %s: wrio t1 [%lx] \n " , __func__ , * len ) ;
qla27xx_write_reg ( reg , IOBASE_ADDR , ent - > t257 . base_addr , buf ) ;
qla27xx_write_reg ( reg , ent - > t257 . pci_offset , ent - > t257 . write_data , buf ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t258 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ql_dbg ( ql_dbg_misc , vha , 0xd202 ,
" %s: rdio t2 [%lx] \n " , __func__ , * len ) ;
qla27xx_write_reg ( reg , ent - > t258 . banksel_offset , ent - > t258 . bank , buf ) ;
qla27xx_read_window ( reg , ent - > t258 . base_addr , ent - > t258 . pci_offset ,
ent - > t258 . reg_count , ent - > t258 . reg_width , buf , len ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t259 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ql_dbg ( ql_dbg_misc , vha , 0xd203 ,
" %s: wrio t2 [%lx] \n " , __func__ , * len ) ;
qla27xx_write_reg ( reg , IOBASE_ADDR , ent - > t259 . base_addr , buf ) ;
qla27xx_write_reg ( reg , ent - > t259 . banksel_offset , ent - > t259 . bank , buf ) ;
qla27xx_write_reg ( reg , ent - > t259 . pci_offset , ent - > t259 . write_data , buf ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t260 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ql_dbg ( ql_dbg_misc , vha , 0xd204 ,
" %s: rdpci [%lx] \n " , __func__ , * len ) ;
2014-04-12 00:54:36 +04:00
qla27xx_insert32 ( ent - > t260 . pci_offset , buf , len ) ;
qla27xx_read_reg ( reg , ent - > t260 . pci_offset , buf , len ) ;
2014-02-26 13:15:06 +04:00
return false ;
}
static int
qla27xx_fwdt_entry_t261 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ql_dbg ( ql_dbg_misc , vha , 0xd205 ,
" %s: wrpci [%lx] \n " , __func__ , * len ) ;
2014-04-12 00:54:36 +04:00
qla27xx_write_reg ( reg , ent - > t261 . pci_offset , ent - > t261 . write_data , buf ) ;
2014-02-26 13:15:06 +04:00
return false ;
}
static int
qla27xx_fwdt_entry_t262 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ulong dwords ;
ulong start ;
ulong end ;
ql_dbg ( ql_dbg_misc , vha , 0xd206 ,
" %s: rdram(%x) [%lx] \n " , __func__ , ent - > t262 . ram_area , * len ) ;
start = ent - > t262 . start_addr ;
end = ent - > t262 . end_addr ;
if ( ent - > t262 . ram_area = = T262_RAM_AREA_CRITICAL_RAM ) {
;
} else if ( ent - > t262 . ram_area = = T262_RAM_AREA_EXTERNAL_RAM ) {
end = vha - > hw - > fw_memory_size ;
if ( buf )
ent - > t262 . end_addr = end ;
} else if ( ent - > t262 . ram_area = = T262_RAM_AREA_SHARED_RAM ) {
start = vha - > hw - > fw_shared_ram_start ;
end = vha - > hw - > fw_shared_ram_end ;
if ( buf ) {
ent - > t262 . start_addr = start ;
ent - > t262 . end_addr = end ;
}
2016-07-06 18:14:18 +03:00
} else if ( ent - > t262 . ram_area = = T262_RAM_AREA_DDR_RAM ) {
start = vha - > hw - > fw_ddr_ram_start ;
end = vha - > hw - > fw_ddr_ram_end ;
if ( buf ) {
ent - > t262 . start_addr = start ;
ent - > t262 . end_addr = end ;
}
2014-02-26 13:15:06 +04:00
} else {
ql_dbg ( ql_dbg_misc , vha , 0xd022 ,
2014-09-25 13:16:40 +04:00
" %s: unknown area %x \n " , __func__ , ent - > t262 . ram_area ) ;
2014-02-26 13:15:06 +04:00
qla27xx_skip_entry ( ent , buf ) ;
goto done ;
}
2017-05-25 04:06:21 +03:00
if ( end < start | | start = = 0 | | end = = 0 ) {
2014-02-26 13:15:06 +04:00
ql_dbg ( ql_dbg_misc , vha , 0xd023 ,
2014-04-12 00:54:36 +04:00
" %s: unusable range (start=%x end=%x) \n " , __func__ ,
2014-02-26 13:15:06 +04:00
ent - > t262 . end_addr , ent - > t262 . start_addr ) ;
qla27xx_skip_entry ( ent , buf ) ;
goto done ;
}
dwords = end - start + 1 ;
if ( buf ) {
buf + = * len ;
qla24xx_dump_ram ( vha - > hw , start , buf , dwords , & buf ) ;
}
* len + = dwords * sizeof ( uint32_t ) ;
done :
return false ;
}
static int
qla27xx_fwdt_entry_t263 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
uint count = 0 ;
uint i ;
uint length ;
ql_dbg ( ql_dbg_misc , vha , 0xd207 ,
" %s: getq(%x) [%lx] \n " , __func__ , ent - > t263 . queue_type , * len ) ;
if ( ent - > t263 . queue_type = = T263_QUEUE_TYPE_REQ ) {
for ( i = 0 ; i < vha - > hw - > max_req_queues ; i + + ) {
struct req_que * req = vha - > hw - > req_q_map [ i ] ;
2016-02-04 19:45:16 +03:00
2014-02-26 13:15:06 +04:00
if ( req | | ! buf ) {
length = req ?
req - > length : REQUEST_ENTRY_CNT_24XX ;
qla27xx_insert16 ( i , buf , len ) ;
qla27xx_insert16 ( length , buf , len ) ;
qla27xx_insertbuf ( req ? req - > ring : NULL ,
length * sizeof ( * req - > ring ) , buf , len ) ;
count + + ;
}
}
} else if ( ent - > t263 . queue_type = = T263_QUEUE_TYPE_RSP ) {
for ( i = 0 ; i < vha - > hw - > max_rsp_queues ; i + + ) {
struct rsp_que * rsp = vha - > hw - > rsp_q_map [ i ] ;
2016-02-04 19:45:16 +03:00
2014-02-26 13:15:06 +04:00
if ( rsp | | ! buf ) {
length = rsp ?
rsp - > length : RESPONSE_ENTRY_CNT_MQ ;
qla27xx_insert16 ( i , buf , len ) ;
qla27xx_insert16 ( length , buf , len ) ;
qla27xx_insertbuf ( rsp ? rsp - > ring : NULL ,
length * sizeof ( * rsp - > ring ) , buf , len ) ;
count + + ;
}
}
2016-12-24 05:06:06 +03:00
} else if ( QLA_TGT_MODE_ENABLED ( ) & &
ent - > t263 . queue_type = = T263_QUEUE_TYPE_ATIO ) {
struct qla_hw_data * ha = vha - > hw ;
struct atio * atr = ha - > tgt . atio_ring ;
if ( atr | | ! buf ) {
length = ha - > tgt . atio_q_length ;
qla27xx_insert16 ( 0 , buf , len ) ;
qla27xx_insert16 ( length , buf , len ) ;
qla27xx_insertbuf ( atr , length * sizeof ( * atr ) , buf , len ) ;
count + + ;
}
2014-02-26 13:15:06 +04:00
} else {
ql_dbg ( ql_dbg_misc , vha , 0xd026 ,
2014-09-25 13:16:40 +04:00
" %s: unknown queue %x \n " , __func__ , ent - > t263 . queue_type ) ;
2014-02-26 13:15:06 +04:00
qla27xx_skip_entry ( ent , buf ) ;
}
2017-08-24 01:05:22 +03:00
if ( buf ) {
if ( count )
ent - > t263 . num_queues = count ;
else
qla27xx_skip_entry ( ent , buf ) ;
}
2014-04-12 00:54:36 +04:00
2014-02-26 13:15:06 +04:00
return false ;
}
static int
qla27xx_fwdt_entry_t264 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ql_dbg ( ql_dbg_misc , vha , 0xd208 ,
" %s: getfce [%lx] \n " , __func__ , * len ) ;
if ( vha - > hw - > fce ) {
if ( buf ) {
ent - > t264 . fce_trace_size = FCE_SIZE ;
ent - > t264 . write_pointer = vha - > hw - > fce_wr ;
ent - > t264 . base_pointer = vha - > hw - > fce_dma ;
ent - > t264 . fce_enable_mb0 = vha - > hw - > fce_mb [ 0 ] ;
ent - > t264 . fce_enable_mb2 = vha - > hw - > fce_mb [ 2 ] ;
ent - > t264 . fce_enable_mb3 = vha - > hw - > fce_mb [ 3 ] ;
ent - > t264 . fce_enable_mb4 = vha - > hw - > fce_mb [ 4 ] ;
ent - > t264 . fce_enable_mb5 = vha - > hw - > fce_mb [ 5 ] ;
ent - > t264 . fce_enable_mb6 = vha - > hw - > fce_mb [ 6 ] ;
}
qla27xx_insertbuf ( vha - > hw - > fce , FCE_SIZE , buf , len ) ;
} else {
ql_dbg ( ql_dbg_misc , vha , 0xd027 ,
" %s: missing fce \n " , __func__ ) ;
qla27xx_skip_entry ( ent , buf ) ;
}
return false ;
}
static int
qla27xx_fwdt_entry_t265 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ql_dbg ( ql_dbg_misc , vha , 0xd209 ,
" %s: pause risc [%lx] \n " , __func__ , * len ) ;
if ( buf )
2014-04-12 00:54:21 +04:00
qla24xx_pause_risc ( reg , vha - > hw ) ;
2014-02-26 13:15:06 +04:00
return false ;
}
static int
qla27xx_fwdt_entry_t266 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ql_dbg ( ql_dbg_misc , vha , 0xd20a ,
" %s: reset risc [%lx] \n " , __func__ , * len ) ;
if ( buf )
qla24xx_soft_reset ( vha - > hw ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t267 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ql_dbg ( ql_dbg_misc , vha , 0xd20b ,
" %s: dis intr [%lx] \n " , __func__ , * len ) ;
qla27xx_write_reg ( reg , ent - > t267 . pci_offset , ent - > t267 . data , buf ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t268 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ql_dbg ( ql_dbg_misc , vha , 0xd20c ,
" %s: gethb(%x) [%lx] \n " , __func__ , ent - > t268 . buf_type , * len ) ;
if ( ent - > t268 . buf_type = = T268_BUF_TYPE_EXTD_TRACE ) {
if ( vha - > hw - > eft ) {
if ( buf ) {
ent - > t268 . buf_size = EFT_SIZE ;
ent - > t268 . start_addr = vha - > hw - > eft_dma ;
}
qla27xx_insertbuf ( vha - > hw - > eft , EFT_SIZE , buf , len ) ;
} else {
ql_dbg ( ql_dbg_misc , vha , 0xd028 ,
" %s: missing eft \n " , __func__ ) ;
qla27xx_skip_entry ( ent , buf ) ;
}
} else {
ql_dbg ( ql_dbg_misc , vha , 0xd02b ,
2014-09-25 13:16:40 +04:00
" %s: unknown buffer %x \n " , __func__ , ent - > t268 . buf_type ) ;
2014-02-26 13:15:06 +04:00
qla27xx_skip_entry ( ent , buf ) ;
}
return false ;
}
static int
qla27xx_fwdt_entry_t269 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ql_dbg ( ql_dbg_misc , vha , 0xd20d ,
" %s: scratch [%lx] \n " , __func__ , * len ) ;
qla27xx_insert32 ( 0xaaaaaaaa , buf , len ) ;
qla27xx_insert32 ( 0xbbbbbbbb , buf , len ) ;
qla27xx_insert32 ( 0xcccccccc , buf , len ) ;
qla27xx_insert32 ( 0xdddddddd , buf , len ) ;
qla27xx_insert32 ( * len + sizeof ( uint32_t ) , buf , len ) ;
if ( buf )
ent - > t269 . scratch_size = 5 * sizeof ( uint32_t ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t270 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ulong dwords = ent - > t270 . count ;
ulong addr = ent - > t270 . addr ;
ql_dbg ( ql_dbg_misc , vha , 0xd20e ,
" %s: rdremreg [%lx] \n " , __func__ , * len ) ;
qla27xx_write_reg ( reg , IOBASE_ADDR , 0x40 , buf ) ;
while ( dwords - - ) {
qla27xx_write_reg ( reg , 0xc0 , addr | 0x80000000 , buf ) ;
qla27xx_insert32 ( addr , buf , len ) ;
2014-04-12 00:54:36 +04:00
qla27xx_read_reg ( reg , 0xc4 , buf , len ) ;
2014-04-12 00:54:23 +04:00
addr + = sizeof ( uint32_t ) ;
2014-02-26 13:15:06 +04:00
}
return false ;
}
static int
qla27xx_fwdt_entry_t271 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
struct device_reg_24xx __iomem * reg = qla27xx_isp_reg ( vha ) ;
ulong addr = ent - > t271 . addr ;
2014-04-12 00:54:08 +04:00
ulong data = ent - > t271 . data ;
2014-02-26 13:15:06 +04:00
ql_dbg ( ql_dbg_misc , vha , 0xd20f ,
" %s: wrremreg [%lx] \n " , __func__ , * len ) ;
qla27xx_write_reg ( reg , IOBASE_ADDR , 0x40 , buf ) ;
2014-04-12 00:54:08 +04:00
qla27xx_write_reg ( reg , 0xc4 , data , buf ) ;
2014-02-26 13:15:06 +04:00
qla27xx_write_reg ( reg , 0xc0 , addr , buf ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t272 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ulong dwords = ent - > t272 . count ;
ulong start = ent - > t272 . addr ;
ql_dbg ( ql_dbg_misc , vha , 0xd210 ,
" %s: rdremram [%lx] \n " , __func__ , * len ) ;
if ( buf ) {
ql_dbg ( ql_dbg_misc , vha , 0xd02c ,
" %s: @%lx -> (%lx dwords) \n " , __func__ , start , dwords ) ;
buf + = * len ;
qla27xx_dump_mpi_ram ( vha - > hw , start , buf , dwords , & buf ) ;
}
* len + = dwords * sizeof ( uint32_t ) ;
return false ;
}
static int
qla27xx_fwdt_entry_t273 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ulong dwords = ent - > t273 . count ;
ulong addr = ent - > t273 . addr ;
uint32_t value ;
ql_dbg ( ql_dbg_misc , vha , 0xd211 ,
" %s: pcicfg [%lx] \n " , __func__ , * len ) ;
while ( dwords - - ) {
value = ~ 0 ;
if ( pci_read_config_dword ( vha - > hw - > pdev , addr , & value ) )
ql_dbg ( ql_dbg_misc , vha , 0xd02d ,
" %s: failed pcicfg read at %lx \n " , __func__ , addr ) ;
qla27xx_insert32 ( addr , buf , len ) ;
qla27xx_insert32 ( value , buf , len ) ;
2014-04-12 00:54:36 +04:00
addr + = sizeof ( uint32_t ) ;
}
return false ;
}
static int
qla27xx_fwdt_entry_t274 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
uint count = 0 ;
uint i ;
ql_dbg ( ql_dbg_misc , vha , 0xd212 ,
" %s: getqsh(%x) [%lx] \n " , __func__ , ent - > t274 . queue_type , * len ) ;
if ( ent - > t274 . queue_type = = T274_QUEUE_TYPE_REQ_SHAD ) {
for ( i = 0 ; i < vha - > hw - > max_req_queues ; i + + ) {
struct req_que * req = vha - > hw - > req_q_map [ i ] ;
2016-02-04 19:45:16 +03:00
2014-04-12 00:54:36 +04:00
if ( req | | ! buf ) {
qla27xx_insert16 ( i , buf , len ) ;
qla27xx_insert16 ( 1 , buf , len ) ;
2014-04-12 00:54:37 +04:00
qla27xx_insert32 ( req & & req - > out_ptr ?
* req - > out_ptr : 0 , buf , len ) ;
2014-04-12 00:54:36 +04:00
count + + ;
}
}
} else if ( ent - > t274 . queue_type = = T274_QUEUE_TYPE_RSP_SHAD ) {
for ( i = 0 ; i < vha - > hw - > max_rsp_queues ; i + + ) {
struct rsp_que * rsp = vha - > hw - > rsp_q_map [ i ] ;
2016-02-04 19:45:16 +03:00
2014-04-12 00:54:36 +04:00
if ( rsp | | ! buf ) {
qla27xx_insert16 ( i , buf , len ) ;
qla27xx_insert16 ( 1 , buf , len ) ;
2014-04-12 00:54:37 +04:00
qla27xx_insert32 ( rsp & & rsp - > in_ptr ?
* rsp - > in_ptr : 0 , buf , len ) ;
2014-04-12 00:54:36 +04:00
count + + ;
}
}
2016-12-24 05:06:06 +03:00
} else if ( QLA_TGT_MODE_ENABLED ( ) & &
ent - > t274 . queue_type = = T274_QUEUE_TYPE_ATIO_SHAD ) {
struct qla_hw_data * ha = vha - > hw ;
struct atio * atr = ha - > tgt . atio_ring_ptr ;
if ( atr | | ! buf ) {
qla27xx_insert16 ( 0 , buf , len ) ;
qla27xx_insert16 ( 1 , buf , len ) ;
qla27xx_insert32 ( ha - > tgt . atio_q_in ?
readl ( ha - > tgt . atio_q_in ) : 0 , buf , len ) ;
count + + ;
}
2014-04-12 00:54:36 +04:00
} else {
ql_dbg ( ql_dbg_misc , vha , 0xd02f ,
2014-09-25 13:16:40 +04:00
" %s: unknown queue %x \n " , __func__ , ent - > t274 . queue_type ) ;
2014-04-12 00:54:36 +04:00
qla27xx_skip_entry ( ent , buf ) ;
2014-02-26 13:15:06 +04:00
}
2017-08-24 01:05:22 +03:00
if ( buf ) {
if ( count )
ent - > t274 . num_queues = count ;
else
qla27xx_skip_entry ( ent , buf ) ;
}
2014-04-12 00:54:36 +04:00
2014-02-26 13:15:06 +04:00
return false ;
}
2014-09-25 13:16:36 +04:00
static int
qla27xx_fwdt_entry_t275 ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ulong offset = offsetof ( typeof ( * ent ) , t275 . buffer ) ;
ql_dbg ( ql_dbg_misc , vha , 0xd213 ,
" %s: buffer(%x) [%lx] \n " , __func__ , ent - > t275 . length , * len ) ;
if ( ! ent - > t275 . length ) {
ql_dbg ( ql_dbg_misc , vha , 0xd020 ,
" %s: buffer zero length \n " , __func__ ) ;
qla27xx_skip_entry ( ent , buf ) ;
goto done ;
}
if ( offset + ent - > t275 . length > ent - > hdr . entry_size ) {
ql_dbg ( ql_dbg_misc , vha , 0xd030 ,
" %s: buffer overflow \n " , __func__ ) ;
qla27xx_skip_entry ( ent , buf ) ;
goto done ;
}
qla27xx_insertbuf ( ent - > t275 . buffer , ent - > t275 . length , buf , len ) ;
done :
return false ;
}
2014-02-26 13:15:06 +04:00
static int
qla27xx_fwdt_entry_other ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_entry * ent , void * buf , ulong * len )
{
ql_dbg ( ql_dbg_misc , vha , 0xd2ff ,
" %s: type %x [%lx] \n " , __func__ , ent - > hdr . entry_type , * len ) ;
qla27xx_skip_entry ( ent , buf ) ;
return false ;
}
struct qla27xx_fwdt_entry_call {
2014-09-25 13:16:33 +04:00
uint type ;
2014-02-26 13:15:06 +04:00
int ( * call ) (
struct scsi_qla_host * ,
struct qla27xx_fwdt_entry * ,
void * ,
ulong * ) ;
} ;
static struct qla27xx_fwdt_entry_call ql27xx_fwdt_entry_call_list [ ] = {
{ ENTRY_TYPE_NOP , qla27xx_fwdt_entry_t0 } ,
{ ENTRY_TYPE_TMP_END , qla27xx_fwdt_entry_t255 } ,
{ ENTRY_TYPE_RD_IOB_T1 , qla27xx_fwdt_entry_t256 } ,
{ ENTRY_TYPE_WR_IOB_T1 , qla27xx_fwdt_entry_t257 } ,
{ ENTRY_TYPE_RD_IOB_T2 , qla27xx_fwdt_entry_t258 } ,
{ ENTRY_TYPE_WR_IOB_T2 , qla27xx_fwdt_entry_t259 } ,
{ ENTRY_TYPE_RD_PCI , qla27xx_fwdt_entry_t260 } ,
{ ENTRY_TYPE_WR_PCI , qla27xx_fwdt_entry_t261 } ,
{ ENTRY_TYPE_RD_RAM , qla27xx_fwdt_entry_t262 } ,
{ ENTRY_TYPE_GET_QUEUE , qla27xx_fwdt_entry_t263 } ,
{ ENTRY_TYPE_GET_FCE , qla27xx_fwdt_entry_t264 } ,
{ ENTRY_TYPE_PSE_RISC , qla27xx_fwdt_entry_t265 } ,
{ ENTRY_TYPE_RST_RISC , qla27xx_fwdt_entry_t266 } ,
{ ENTRY_TYPE_DIS_INTR , qla27xx_fwdt_entry_t267 } ,
{ ENTRY_TYPE_GET_HBUF , qla27xx_fwdt_entry_t268 } ,
{ ENTRY_TYPE_SCRATCH , qla27xx_fwdt_entry_t269 } ,
{ ENTRY_TYPE_RDREMREG , qla27xx_fwdt_entry_t270 } ,
{ ENTRY_TYPE_WRREMREG , qla27xx_fwdt_entry_t271 } ,
{ ENTRY_TYPE_RDREMRAM , qla27xx_fwdt_entry_t272 } ,
{ ENTRY_TYPE_PCICFG , qla27xx_fwdt_entry_t273 } ,
2014-04-12 00:54:36 +04:00
{ ENTRY_TYPE_GET_SHADOW , qla27xx_fwdt_entry_t274 } ,
2014-09-25 13:16:36 +04:00
{ ENTRY_TYPE_WRITE_BUF , qla27xx_fwdt_entry_t275 } ,
2014-02-26 13:15:06 +04:00
{ - 1 , qla27xx_fwdt_entry_other }
} ;
2014-09-25 13:16:33 +04:00
static inline int ( * qla27xx_find_entry ( uint type ) )
2014-02-26 13:15:06 +04:00
( struct scsi_qla_host * , struct qla27xx_fwdt_entry * , void * , ulong * )
{
struct qla27xx_fwdt_entry_call * list = ql27xx_fwdt_entry_call_list ;
2014-09-25 13:16:33 +04:00
while ( list - > type < type )
2014-02-26 13:15:06 +04:00
list + + ;
2014-09-25 13:16:33 +04:00
if ( list - > type = = type )
return list - > call ;
return qla27xx_fwdt_entry_other ;
2014-02-26 13:15:06 +04:00
}
static inline void *
qla27xx_next_entry ( void * p )
{
struct qla27xx_fwdt_entry * ent = p ;
return p + ent - > hdr . entry_size ;
}
static void
qla27xx_walk_template ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_template * tmp , void * buf , ulong * len )
{
struct qla27xx_fwdt_entry * ent = ( void * ) tmp + tmp - > entry_offset ;
ulong count = tmp - > entry_count ;
ql_dbg ( ql_dbg_misc , vha , 0xd01a ,
" %s: entry count %lx \n " , __func__ , count ) ;
while ( count - - ) {
2017-06-02 19:11:55 +03:00
if ( buf & & * len > = vha - > hw - > fw_dump_len )
break ;
2014-02-26 13:15:06 +04:00
if ( qla27xx_find_entry ( ent - > hdr . entry_type ) ( vha , ent , buf , len ) )
break ;
ent = qla27xx_next_entry ( ent ) ;
}
2014-09-25 13:16:32 +04:00
if ( count )
ql_dbg ( ql_dbg_misc , vha , 0xd018 ,
2017-06-02 19:11:55 +03:00
" %s: entry residual count (%lx) \n " , __func__ , count ) ;
2014-09-25 13:16:32 +04:00
if ( ent - > hdr . entry_type ! = ENTRY_TYPE_TMP_END )
ql_dbg ( ql_dbg_misc , vha , 0xd019 ,
2017-06-02 19:11:55 +03:00
" %s: missing end entry (%lx) \n " , __func__ , count ) ;
2014-09-25 13:16:32 +04:00
2017-06-02 19:11:55 +03:00
if ( buf & & * len ! = vha - > hw - > fw_dump_len )
ql_dbg ( ql_dbg_misc , vha , 0xd01b ,
" %s: length=%#lx residual=%+ld \n " ,
__func__ , * len , vha - > hw - > fw_dump_len - * len ) ;
2015-04-09 22:00:00 +03:00
2015-04-09 22:00:01 +03:00
if ( buf ) {
2015-04-09 22:00:00 +03:00
ql_log ( ql_log_warn , vha , 0xd015 ,
2017-06-02 19:11:55 +03:00
" Firmware dump saved to temp buffer (%lu/%p) \n " ,
2015-04-09 22:00:00 +03:00
vha - > host_no , vha - > hw - > fw_dump ) ;
2015-04-09 22:00:01 +03:00
qla2x00_post_uevent_work ( vha , QLA_UEVENT_CODE_FW_DUMP ) ;
}
2014-02-26 13:15:06 +04:00
}
static void
qla27xx_time_stamp ( struct qla27xx_fwdt_template * tmp )
{
tmp - > capture_timestamp = jiffies ;
}
static void
qla27xx_driver_info ( struct qla27xx_fwdt_template * tmp )
{
uint8_t v [ ] = { 0 , 0 , 0 , 0 , 0 , 0 } ;
2015-07-09 17:23:26 +03:00
sscanf ( qla2x00_version_str , " %hhu.%hhu.%hhu.%hhu.%hhu.%hhu " ,
2014-02-26 13:15:06 +04:00
v + 0 , v + 1 , v + 2 , v + 3 , v + 4 , v + 5 ) ;
tmp - > driver_info [ 0 ] = v [ 3 ] < < 24 | v [ 2 ] < < 16 | v [ 1 ] < < 8 | v [ 0 ] ;
tmp - > driver_info [ 1 ] = v [ 5 ] < < 8 | v [ 4 ] ;
tmp - > driver_info [ 2 ] = 0x12345678 ;
}
static void
qla27xx_firmware_info ( struct qla27xx_fwdt_template * tmp ,
struct scsi_qla_host * vha )
{
tmp - > firmware_version [ 0 ] = vha - > hw - > fw_major_version ;
tmp - > firmware_version [ 1 ] = vha - > hw - > fw_minor_version ;
tmp - > firmware_version [ 2 ] = vha - > hw - > fw_subminor_version ;
tmp - > firmware_version [ 3 ] =
vha - > hw - > fw_attributes_h < < 16 | vha - > hw - > fw_attributes ;
tmp - > firmware_version [ 4 ] =
vha - > hw - > fw_attributes_ext [ 1 ] < < 16 | vha - > hw - > fw_attributes_ext [ 0 ] ;
}
static void
ql27xx_edit_template ( struct scsi_qla_host * vha ,
struct qla27xx_fwdt_template * tmp )
{
qla27xx_time_stamp ( tmp ) ;
qla27xx_driver_info ( tmp ) ;
qla27xx_firmware_info ( tmp , vha ) ;
}
static inline uint32_t
qla27xx_template_checksum ( void * p , ulong size )
{
uint32_t * buf = p ;
uint64_t sum = 0 ;
size / = sizeof ( * buf ) ;
while ( size - - )
sum + = * buf + + ;
sum = ( sum & 0xffffffff ) + ( sum > > 32 ) ;
return ~ sum ;
}
static inline int
qla27xx_verify_template_checksum ( struct qla27xx_fwdt_template * tmp )
{
return qla27xx_template_checksum ( tmp , tmp - > template_size ) = = 0 ;
}
static inline int
qla27xx_verify_template_header ( struct qla27xx_fwdt_template * tmp )
{
return tmp - > template_type = = TEMPLATE_TYPE_FWDUMP ;
}
static void
qla27xx_execute_fwdt_template ( struct scsi_qla_host * vha )
{
struct qla27xx_fwdt_template * tmp = vha - > hw - > fw_dump_template ;
ulong len ;
if ( qla27xx_fwdt_template_valid ( tmp ) ) {
len = tmp - > template_size ;
tmp = memcpy ( vha - > hw - > fw_dump , tmp , len ) ;
ql27xx_edit_template ( vha , tmp ) ;
qla27xx_walk_template ( vha , tmp , tmp , & len ) ;
vha - > hw - > fw_dump_len = len ;
vha - > hw - > fw_dumped = 1 ;
}
}
ulong
qla27xx_fwdt_calculate_dump_size ( struct scsi_qla_host * vha )
{
struct qla27xx_fwdt_template * tmp = vha - > hw - > fw_dump_template ;
ulong len = 0 ;
if ( qla27xx_fwdt_template_valid ( tmp ) ) {
len = tmp - > template_size ;
qla27xx_walk_template ( vha , tmp , NULL , & len ) ;
}
return len ;
}
ulong
qla27xx_fwdt_template_size ( void * p )
{
struct qla27xx_fwdt_template * tmp = p ;
return tmp - > template_size ;
}
ulong
qla27xx_fwdt_template_default_size ( void )
{
return sizeof ( ql27xx_fwdt_default_template ) ;
}
const void *
qla27xx_fwdt_template_default ( void )
{
return ql27xx_fwdt_default_template ;
}
int
qla27xx_fwdt_template_valid ( void * p )
{
struct qla27xx_fwdt_template * tmp = p ;
if ( ! qla27xx_verify_template_header ( tmp ) ) {
ql_log ( ql_log_warn , NULL , 0xd01c ,
" %s: template type %x \n " , __func__ , tmp - > template_type ) ;
return false ;
}
if ( ! qla27xx_verify_template_checksum ( tmp ) ) {
ql_log ( ql_log_warn , NULL , 0xd01d ,
" %s: failed template checksum \n " , __func__ ) ;
return false ;
}
return true ;
}
void
qla27xx_fwdump ( scsi_qla_host_t * vha , int hardware_locked )
{
ulong flags = 0 ;
2015-07-09 17:25:46 +03:00
# ifndef __CHECKER__
2014-02-26 13:15:06 +04:00
if ( ! hardware_locked )
spin_lock_irqsave ( & vha - > hw - > hardware_lock , flags ) ;
2015-07-09 17:25:46 +03:00
# endif
2014-02-26 13:15:06 +04:00
if ( ! vha - > hw - > fw_dump )
ql_log ( ql_log_warn , vha , 0xd01e , " fwdump buffer missing. \n " ) ;
else if ( ! vha - > hw - > fw_dump_template )
ql_log ( ql_log_warn , vha , 0xd01f , " fwdump template missing. \n " ) ;
2015-04-09 22:00:05 +03:00
else if ( vha - > hw - > fw_dumped )
ql_log ( ql_log_warn , vha , 0xd300 ,
" Firmware has been previously dumped (%p), "
" -- ignoring request \n " , vha - > hw - > fw_dump ) ;
2014-02-26 13:15:06 +04:00
else
qla27xx_execute_fwdt_template ( vha ) ;
2015-07-09 17:25:46 +03:00
# ifndef __CHECKER__
2014-02-26 13:15:06 +04:00
if ( ! hardware_locked )
spin_unlock_irqrestore ( & vha - > hw - > hardware_lock , flags ) ;
2015-07-09 17:25:46 +03:00
# endif
2014-02-26 13:15:06 +04:00
}