2006-09-19 21:28:00 +04:00
/*
* QLogic iSCSI HBA Driver
2013-08-16 15:03:04 +04:00
* Copyright ( c ) 2003 - 2013 QLogic Corporation
2006-09-19 21:28:00 +04:00
*
* See LICENSE . qla4xxx for copyright and licensing details .
*/
# include "ql4_def.h"
2007-05-24 05:14:34 +04:00
# include "ql4_glbl.h"
# include "ql4_dbg.h"
# include "ql4_inline.h"
2006-09-19 21:28:00 +04:00
2006-11-21 03:20:22 +03:00
static inline void eeprom_cmd ( uint32_t cmd , struct scsi_qla_host * ha )
{
writel ( cmd , isp_nvram ( ha ) ) ;
readl ( isp_nvram ( ha ) ) ;
udelay ( 1 ) ;
}
2006-09-19 21:28:00 +04:00
static inline int eeprom_size ( struct scsi_qla_host * ha )
{
2006-11-16 04:38:40 +03:00
return is_qla4010 ( ha ) ? FM93C66A_SIZE_16 : FM93C86A_SIZE_16 ;
2006-09-19 21:28:00 +04:00
}
static inline int eeprom_no_addr_bits ( struct scsi_qla_host * ha )
{
2006-11-16 04:38:40 +03:00
return is_qla4010 ( ha ) ? FM93C56A_NO_ADDR_BITS_16 :
FM93C86A_NO_ADDR_BITS_16 ;
2006-09-19 21:28:00 +04:00
}
static inline int eeprom_no_data_bits ( struct scsi_qla_host * ha )
{
return FM93C56A_DATA_BITS_16 ;
}
static int fm93c56a_select ( struct scsi_qla_host * ha )
{
DEBUG5 ( printk ( KERN_ERR " fm93c56a_select: \n " ) ) ;
ha - > eeprom_cmd_data = AUBURN_EEPROM_CS_1 | 0x000f0000 ;
2006-11-21 03:20:22 +03:00
eeprom_cmd ( ha - > eeprom_cmd_data , ha ) ;
2006-09-19 21:28:00 +04:00
return 1 ;
}
static int fm93c56a_cmd ( struct scsi_qla_host * ha , int cmd , int addr )
{
int i ;
int mask ;
int dataBit ;
int previousBit ;
/* Clock in a zero, then do the start bit. */
2006-11-21 03:20:22 +03:00
eeprom_cmd ( ha - > eeprom_cmd_data | AUBURN_EEPROM_DO_1 , ha ) ;
eeprom_cmd ( ha - > eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
AUBURN_EEPROM_CLK_RISE , ha ) ;
eeprom_cmd ( ha - > eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
AUBURN_EEPROM_CLK_FALL , ha ) ;
2006-09-19 21:28:00 +04:00
mask = 1 < < ( FM93C56A_CMD_BITS - 1 ) ;
/* Force the previous data bit to be different. */
previousBit = 0xffff ;
for ( i = 0 ; i < FM93C56A_CMD_BITS ; i + + ) {
dataBit =
( cmd & mask ) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0 ;
if ( previousBit ! = dataBit ) {
/*
* If the bit changed , then change the DO state to
* match .
*/
2006-11-21 03:20:22 +03:00
eeprom_cmd ( ha - > eeprom_cmd_data | dataBit , ha ) ;
2006-09-19 21:28:00 +04:00
previousBit = dataBit ;
}
2006-11-21 03:20:22 +03:00
eeprom_cmd ( ha - > eeprom_cmd_data | dataBit |
AUBURN_EEPROM_CLK_RISE , ha ) ;
eeprom_cmd ( ha - > eeprom_cmd_data | dataBit |
AUBURN_EEPROM_CLK_FALL , ha ) ;
2006-09-19 21:28:00 +04:00
cmd = cmd < < 1 ;
}
mask = 1 < < ( eeprom_no_addr_bits ( ha ) - 1 ) ;
/* Force the previous data bit to be different. */
previousBit = 0xffff ;
for ( i = 0 ; i < eeprom_no_addr_bits ( ha ) ; i + + ) {
dataBit = addr & mask ? AUBURN_EEPROM_DO_1 :
AUBURN_EEPROM_DO_0 ;
if ( previousBit ! = dataBit ) {
/*
* If the bit changed , then change the DO state to
* match .
*/
2006-11-21 03:20:22 +03:00
eeprom_cmd ( ha - > eeprom_cmd_data | dataBit , ha ) ;
2006-09-19 21:28:00 +04:00
previousBit = dataBit ;
}
2006-11-21 03:20:22 +03:00
eeprom_cmd ( ha - > eeprom_cmd_data | dataBit |
AUBURN_EEPROM_CLK_RISE , ha ) ;
eeprom_cmd ( ha - > eeprom_cmd_data | dataBit |
AUBURN_EEPROM_CLK_FALL , ha ) ;
2006-09-19 21:28:00 +04:00
addr = addr < < 1 ;
}
return 1 ;
}
static int fm93c56a_deselect ( struct scsi_qla_host * ha )
{
ha - > eeprom_cmd_data = AUBURN_EEPROM_CS_0 | 0x000f0000 ;
2006-11-21 03:20:22 +03:00
eeprom_cmd ( ha - > eeprom_cmd_data , ha ) ;
2006-09-19 21:28:00 +04:00
return 1 ;
}
static int fm93c56a_datain ( struct scsi_qla_host * ha , unsigned short * value )
{
int i ;
int data = 0 ;
int dataBit ;
/* Read the data bits
* The first bit is a dummy . Clock right over it . */
for ( i = 0 ; i < eeprom_no_data_bits ( ha ) ; i + + ) {
2006-11-21 03:20:22 +03:00
eeprom_cmd ( ha - > eeprom_cmd_data |
AUBURN_EEPROM_CLK_RISE , ha ) ;
eeprom_cmd ( ha - > eeprom_cmd_data |
AUBURN_EEPROM_CLK_FALL , ha ) ;
dataBit = ( readw ( isp_nvram ( ha ) ) & AUBURN_EEPROM_DI_1 ) ? 1 : 0 ;
2006-09-19 21:28:00 +04:00
data = ( data < < 1 ) | dataBit ;
}
* value = data ;
return 1 ;
}
static int eeprom_readword ( int eepromAddr , u16 * value ,
struct scsi_qla_host * ha )
{
fm93c56a_select ( ha ) ;
fm93c56a_cmd ( ha , FM93C56A_READ , eepromAddr ) ;
fm93c56a_datain ( ha , value ) ;
fm93c56a_deselect ( ha ) ;
return 1 ;
}
/* Hardware_lock must be set before calling */
u16 rd_nvram_word ( struct scsi_qla_host * ha , int offset )
{
2010-07-28 14:23:44 +04:00
u16 val = 0 ;
2006-09-19 21:28:00 +04:00
/* NOTE: NVRAM uses half-word addresses */
eeprom_readword ( offset , & val , ha ) ;
return val ;
}
2011-07-25 22:48:55 +04:00
u8 rd_nvram_byte ( struct scsi_qla_host * ha , int offset )
{
u16 val = 0 ;
u8 rval = 0 ;
int index = 0 ;
if ( offset & 0x1 )
index = ( offset - 1 ) / 2 ;
else
index = offset / 2 ;
val = le16_to_cpu ( rd_nvram_word ( ha , index ) ) ;
if ( offset & 0x1 )
rval = ( u8 ) ( ( val & 0xff00 ) > > 8 ) ;
else
rval = ( u8 ) ( ( val & 0x00ff ) ) ;
return rval ;
}
2006-09-19 21:28:00 +04:00
int qla4xxx_is_nvram_configuration_valid ( struct scsi_qla_host * ha )
{
int status = QLA_ERROR ;
uint16_t checksum = 0 ;
uint32_t index ;
unsigned long flags ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
for ( index = 0 ; index < eeprom_size ( ha ) ; index + + )
checksum + = rd_nvram_word ( ha , index ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
if ( checksum = = 0 )
status = QLA_SUCCESS ;
return status ;
}
/*************************************************************************
*
* Hardware Semaphore routines
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int ql4xxx_sem_spinlock ( struct scsi_qla_host * ha , u32 sem_mask , u32 sem_bits )
{
uint32_t value ;
unsigned long flags ;
unsigned int seconds = 30 ;
DEBUG2 ( printk ( " scsi%ld : Trying to get SEM lock - mask= 0x%x, code = "
" 0x%x \n " , ha - > host_no , sem_mask , sem_bits ) ) ;
do {
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
writel ( ( sem_mask | sem_bits ) , isp_semaphore ( ha ) ) ;
value = readw ( isp_semaphore ( ha ) ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
if ( ( value & ( sem_mask > > 16 ) ) = = sem_bits ) {
DEBUG2 ( printk ( " scsi%ld : Got SEM LOCK - mask= 0x%x, "
" code = 0x%x \n " , ha - > host_no ,
sem_mask , sem_bits ) ) ;
return QLA_SUCCESS ;
}
ssleep ( 1 ) ;
} while ( - - seconds ) ;
return QLA_ERROR ;
}
void ql4xxx_sem_unlock ( struct scsi_qla_host * ha , u32 sem_mask )
{
unsigned long flags ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
writel ( sem_mask , isp_semaphore ( ha ) ) ;
readl ( isp_semaphore ( ha ) ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
DEBUG2 ( printk ( " scsi%ld : UNLOCK SEM - mask= 0x%x \n " , ha - > host_no ,
sem_mask ) ) ;
}
int ql4xxx_sem_lock ( struct scsi_qla_host * ha , u32 sem_mask , u32 sem_bits )
{
uint32_t value ;
unsigned long flags ;
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
writel ( ( sem_mask | sem_bits ) , isp_semaphore ( ha ) ) ;
value = readw ( isp_semaphore ( ha ) ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
if ( ( value & ( sem_mask > > 16 ) ) = = sem_bits ) {
DEBUG2 ( printk ( " scsi%ld : Got SEM LOCK - mask= 0x%x, code = "
" 0x%x, sema code=0x%x \n " , ha - > host_no ,
sem_mask , sem_bits , value ) ) ;
return 1 ;
}
return 0 ;
}