2005-04-18 00:04:54 +04:00
/*
2005-10-27 22:10:08 +04:00
* QLogic Fibre Channel HBA Driver
* Copyright ( c ) 2003 - 2005 QLogic Corporation
2005-04-18 00:04:54 +04:00
*
2005-10-27 22:10:08 +04:00
* See LICENSE . qla2xxx for copyright and licensing details .
2005-04-18 00:04:54 +04:00
*/
# include "qla_def.h"
2005-04-18 01:32:42 +04:00
# include <linux/vmalloc.h>
2005-04-18 00:04:54 +04:00
/* SYSFS attributes --------------------------------------------------------- */
static ssize_t
qla2x00_sysfs_read_fw_dump ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
2006-06-24 03:10:29 +04:00
char * rbuf = ( char * ) ha - > fw_dump ;
2005-04-18 00:04:54 +04:00
if ( ha - > fw_dump_reading = = 0 )
return 0 ;
2006-06-24 03:10:29 +04:00
if ( off > ha - > fw_dump_len )
return 0 ;
if ( off + count > ha - > fw_dump_len )
count = ha - > fw_dump_len - off ;
2005-04-18 00:04:54 +04:00
2006-06-24 03:10:29 +04:00
memcpy ( buf , & rbuf [ off ] , count ) ;
2005-04-18 00:04:54 +04:00
return ( count ) ;
}
static ssize_t
qla2x00_sysfs_write_fw_dump ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
int reading ;
if ( off ! = 0 )
return ( 0 ) ;
reading = simple_strtol ( buf , NULL , 10 ) ;
switch ( reading ) {
case 0 :
2006-06-24 03:10:29 +04:00
if ( ! ha - > fw_dump_reading )
break ;
2005-04-18 00:04:54 +04:00
2006-06-24 03:10:29 +04:00
qla_printk ( KERN_INFO , ha ,
" Firmware dump cleared on (%ld). \n " , ha - > host_no ) ;
ha - > fw_dump_reading = 0 ;
ha - > fw_dumped = 0 ;
2005-04-18 00:04:54 +04:00
break ;
case 1 :
2006-05-18 02:09:50 +04:00
if ( ha - > fw_dumped & & ! ha - > fw_dump_reading ) {
2005-04-18 00:04:54 +04:00
ha - > fw_dump_reading = 1 ;
qla_printk ( KERN_INFO , ha ,
2006-06-24 03:10:29 +04:00
" Raw firmware dump ready for read on (%ld). \n " ,
2005-04-18 00:04:54 +04:00
ha - > host_no ) ;
}
break ;
2006-06-24 03:10:29 +04:00
case 2 :
qla2x00_alloc_fw_dump ( ha ) ;
break ;
2005-04-18 00:04:54 +04:00
}
return ( count ) ;
}
static struct bin_attribute sysfs_fw_dump_attr = {
. attr = {
. name = " fw_dump " ,
. mode = S_IRUSR | S_IWUSR ,
. owner = THIS_MODULE ,
} ,
. size = 0 ,
. read = qla2x00_sysfs_read_fw_dump ,
. write = qla2x00_sysfs_write_fw_dump ,
} ;
static ssize_t
qla2x00_sysfs_read_nvram ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
unsigned long flags ;
2006-02-01 03:05:12 +03:00
if ( ! capable ( CAP_SYS_ADMIN ) | | off ! = 0 )
2005-04-18 00:04:54 +04:00
return 0 ;
/* Read NVRAM. */
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
2005-07-06 21:31:07 +04:00
ha - > isp_ops . read_nvram ( ha , ( uint8_t * ) buf , ha - > nvram_base ,
ha - > nvram_size ) ;
2005-04-18 00:04:54 +04:00
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
2006-02-01 03:05:12 +03:00
return ha - > nvram_size ;
2005-04-18 00:04:54 +04:00
}
static ssize_t
qla2x00_sysfs_write_nvram ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
unsigned long flags ;
uint16_t cnt ;
2005-07-06 21:31:07 +04:00
if ( ! capable ( CAP_SYS_ADMIN ) | | off ! = 0 | | count ! = ha - > nvram_size )
2005-04-18 00:04:54 +04:00
return 0 ;
/* Checksum NVRAM. */
2006-03-10 01:27:13 +03:00
if ( IS_QLA24XX ( ha ) | | IS_QLA54XX ( ha ) ) {
2005-07-06 21:31:07 +04:00
uint32_t * iter ;
uint32_t chksum ;
iter = ( uint32_t * ) buf ;
chksum = 0 ;
for ( cnt = 0 ; cnt < ( ( count > > 2 ) - 1 ) ; cnt + + )
chksum + = le32_to_cpu ( * iter + + ) ;
chksum = ~ chksum + 1 ;
* iter = cpu_to_le32 ( chksum ) ;
} else {
uint8_t * iter ;
uint8_t chksum ;
iter = ( uint8_t * ) buf ;
chksum = 0 ;
for ( cnt = 0 ; cnt < count - 1 ; cnt + + )
chksum + = * iter + + ;
chksum = ~ chksum + 1 ;
* iter = chksum ;
}
2005-04-18 00:04:54 +04:00
/* Write NVRAM. */
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
2005-07-06 21:31:07 +04:00
ha - > isp_ops . write_nvram ( ha , ( uint8_t * ) buf , ha - > nvram_base , count ) ;
2005-04-18 00:04:54 +04:00
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
return ( count ) ;
}
static struct bin_attribute sysfs_nvram_attr = {
. attr = {
. name = " nvram " ,
. mode = S_IRUSR | S_IWUSR ,
. owner = THIS_MODULE ,
} ,
2006-02-01 03:05:12 +03:00
. size = 512 ,
2005-04-18 00:04:54 +04:00
. read = qla2x00_sysfs_read_nvram ,
. write = qla2x00_sysfs_write_nvram ,
} ;
2006-02-01 03:05:17 +03:00
static ssize_t
qla2x00_sysfs_read_optrom ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
if ( ha - > optrom_state ! = QLA_SREADING )
return 0 ;
if ( off > ha - > optrom_size )
return 0 ;
if ( off + count > ha - > optrom_size )
count = ha - > optrom_size - off ;
memcpy ( buf , & ha - > optrom_buffer [ off ] , count ) ;
return count ;
}
static ssize_t
qla2x00_sysfs_write_optrom ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
if ( ha - > optrom_state ! = QLA_SWRITING )
return - EINVAL ;
if ( off > ha - > optrom_size )
return - ERANGE ;
if ( off + count > ha - > optrom_size )
count = ha - > optrom_size - off ;
memcpy ( & ha - > optrom_buffer [ off ] , buf , count ) ;
return count ;
}
static struct bin_attribute sysfs_optrom_attr = {
. attr = {
. name = " optrom " ,
. mode = S_IRUSR | S_IWUSR ,
. owner = THIS_MODULE ,
} ,
. size = OPTROM_SIZE_24XX ,
. read = qla2x00_sysfs_read_optrom ,
. write = qla2x00_sysfs_write_optrom ,
} ;
static ssize_t
qla2x00_sysfs_write_optrom_ctl ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
int val ;
if ( off )
return 0 ;
if ( sscanf ( buf , " %d " , & val ) ! = 1 )
return - EINVAL ;
switch ( val ) {
case 0 :
if ( ha - > optrom_state ! = QLA_SREADING & &
ha - > optrom_state ! = QLA_SWRITING )
break ;
ha - > optrom_state = QLA_SWAITING ;
vfree ( ha - > optrom_buffer ) ;
ha - > optrom_buffer = NULL ;
break ;
case 1 :
if ( ha - > optrom_state ! = QLA_SWAITING )
break ;
ha - > optrom_state = QLA_SREADING ;
ha - > optrom_buffer = ( uint8_t * ) vmalloc ( ha - > optrom_size ) ;
if ( ha - > optrom_buffer = = NULL ) {
qla_printk ( KERN_WARNING , ha ,
" Unable to allocate memory for optrom retrieval "
" (%x). \n " , ha - > optrom_size ) ;
ha - > optrom_state = QLA_SWAITING ;
return count ;
}
memset ( ha - > optrom_buffer , 0 , ha - > optrom_size ) ;
ha - > isp_ops . read_optrom ( ha , ha - > optrom_buffer , 0 ,
ha - > optrom_size ) ;
break ;
case 2 :
if ( ha - > optrom_state ! = QLA_SWAITING )
break ;
ha - > optrom_state = QLA_SWRITING ;
ha - > optrom_buffer = ( uint8_t * ) vmalloc ( ha - > optrom_size ) ;
if ( ha - > optrom_buffer = = NULL ) {
qla_printk ( KERN_WARNING , ha ,
" Unable to allocate memory for optrom update "
" (%x). \n " , ha - > optrom_size ) ;
ha - > optrom_state = QLA_SWAITING ;
return count ;
}
memset ( ha - > optrom_buffer , 0 , ha - > optrom_size ) ;
break ;
case 3 :
if ( ha - > optrom_state ! = QLA_SWRITING )
break ;
ha - > isp_ops . write_optrom ( ha , ha - > optrom_buffer , 0 ,
ha - > optrom_size ) ;
break ;
}
return count ;
}
static struct bin_attribute sysfs_optrom_ctl_attr = {
. attr = {
. name = " optrom_ctl " ,
. mode = S_IWUSR ,
. owner = THIS_MODULE ,
} ,
. size = 0 ,
. write = qla2x00_sysfs_write_optrom_ctl ,
} ;
2006-03-10 01:27:34 +03:00
static ssize_t
qla2x00_sysfs_read_vpd ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
unsigned long flags ;
if ( ! capable ( CAP_SYS_ADMIN ) | | off ! = 0 )
return 0 ;
/* Read NVRAM. */
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
ha - > isp_ops . read_nvram ( ha , ( uint8_t * ) buf , ha - > vpd_base , ha - > vpd_size ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
return ha - > vpd_size ;
}
static ssize_t
qla2x00_sysfs_write_vpd ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
unsigned long flags ;
if ( ! capable ( CAP_SYS_ADMIN ) | | off ! = 0 | | count ! = ha - > vpd_size )
return 0 ;
/* Write NVRAM. */
spin_lock_irqsave ( & ha - > hardware_lock , flags ) ;
ha - > isp_ops . write_nvram ( ha , ( uint8_t * ) buf , ha - > vpd_base , count ) ;
spin_unlock_irqrestore ( & ha - > hardware_lock , flags ) ;
return count ;
}
static struct bin_attribute sysfs_vpd_attr = {
. attr = {
. name = " vpd " ,
. mode = S_IRUSR | S_IWUSR ,
. owner = THIS_MODULE ,
} ,
. size = 0 ,
. read = qla2x00_sysfs_read_vpd ,
. write = qla2x00_sysfs_write_vpd ,
} ;
2006-06-24 03:10:50 +04:00
static ssize_t
qla2x00_sysfs_read_sfp ( struct kobject * kobj , char * buf , loff_t off ,
size_t count )
{
struct scsi_qla_host * ha = to_qla_host ( dev_to_shost ( container_of ( kobj ,
struct device , kobj ) ) ) ;
uint16_t iter , addr , offset ;
int rval ;
if ( ! capable ( CAP_SYS_ADMIN ) | | off ! = 0 | | count ! = SFP_DEV_SIZE * 2 )
return 0 ;
addr = 0xa0 ;
for ( iter = 0 , offset = 0 ; iter < ( SFP_DEV_SIZE * 2 ) / SFP_BLOCK_SIZE ;
iter + + , offset + = SFP_BLOCK_SIZE ) {
if ( iter = = 4 ) {
/* Skip to next device address. */
addr = 0xa2 ;
offset = 0 ;
}
rval = qla2x00_read_sfp ( ha , ha - > sfp_data_dma , addr , offset ,
SFP_BLOCK_SIZE ) ;
if ( rval ! = QLA_SUCCESS ) {
qla_printk ( KERN_WARNING , ha ,
" Unable to read SFP data (%x/%x/%x). \n " , rval ,
addr , offset ) ;
count = 0 ;
break ;
}
memcpy ( buf , ha - > sfp_data , SFP_BLOCK_SIZE ) ;
buf + = SFP_BLOCK_SIZE ;
}
return count ;
}
static struct bin_attribute sysfs_sfp_attr = {
. attr = {
. name = " sfp " ,
. mode = S_IRUSR | S_IWUSR ,
. owner = THIS_MODULE ,
} ,
. size = SFP_DEV_SIZE * 2 ,
. read = qla2x00_sysfs_read_sfp ,
} ;
2005-04-18 00:04:54 +04:00
void
qla2x00_alloc_sysfs_attr ( scsi_qla_host_t * ha )
{
struct Scsi_Host * host = ha - > host ;
sysfs_create_bin_file ( & host - > shost_gendev . kobj , & sysfs_fw_dump_attr ) ;
sysfs_create_bin_file ( & host - > shost_gendev . kobj , & sysfs_nvram_attr ) ;
2006-02-01 03:05:17 +03:00
sysfs_create_bin_file ( & host - > shost_gendev . kobj , & sysfs_optrom_attr ) ;
sysfs_create_bin_file ( & host - > shost_gendev . kobj ,
& sysfs_optrom_ctl_attr ) ;
2006-06-24 03:10:55 +04:00
if ( IS_QLA24XX ( ha ) | | IS_QLA54XX ( ha ) ) {
sysfs_create_bin_file ( & host - > shost_gendev . kobj ,
& sysfs_vpd_attr ) ;
2006-06-24 03:10:50 +04:00
sysfs_create_bin_file ( & host - > shost_gendev . kobj ,
& sysfs_sfp_attr ) ;
2006-06-24 03:10:55 +04:00
}
2005-04-18 00:04:54 +04:00
}
void
qla2x00_free_sysfs_attr ( scsi_qla_host_t * ha )
{
struct Scsi_Host * host = ha - > host ;
sysfs_remove_bin_file ( & host - > shost_gendev . kobj , & sysfs_fw_dump_attr ) ;
sysfs_remove_bin_file ( & host - > shost_gendev . kobj , & sysfs_nvram_attr ) ;
2006-02-01 03:05:17 +03:00
sysfs_remove_bin_file ( & host - > shost_gendev . kobj , & sysfs_optrom_attr ) ;
sysfs_remove_bin_file ( & host - > shost_gendev . kobj ,
& sysfs_optrom_ctl_attr ) ;
2006-06-24 03:10:55 +04:00
if ( IS_QLA24XX ( ha ) | | IS_QLA54XX ( ha ) ) {
sysfs_remove_bin_file ( & host - > shost_gendev . kobj ,
& sysfs_vpd_attr ) ;
2006-06-24 03:10:50 +04:00
sysfs_remove_bin_file ( & host - > shost_gendev . kobj ,
& sysfs_sfp_attr ) ;
2006-06-24 03:10:55 +04:00
}
2006-02-01 03:05:07 +03:00
if ( ha - > beacon_blink_led = = 1 )
ha - > isp_ops . beacon_off ( ha ) ;
2005-04-18 00:04:54 +04:00
}
2005-08-27 06:09:40 +04:00
/* Scsi_Host attributes. */
static ssize_t
qla2x00_drvr_version_show ( struct class_device * cdev , char * buf )
{
return snprintf ( buf , PAGE_SIZE , " %s \n " , qla2x00_version_str ) ;
}
static ssize_t
qla2x00_fw_version_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
char fw_str [ 30 ] ;
return snprintf ( buf , PAGE_SIZE , " %s \n " ,
ha - > isp_ops . fw_version_str ( ha , fw_str ) ) ;
}
static ssize_t
qla2x00_serial_num_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
uint32_t sn ;
sn = ( ( ha - > serial0 & 0x1f ) < < 16 ) | ( ha - > serial2 < < 8 ) | ha - > serial1 ;
return snprintf ( buf , PAGE_SIZE , " %c%05d \n " , ' A ' + sn / 100000 ,
sn % 100000 ) ;
}
static ssize_t
qla2x00_isp_name_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
2005-11-10 02:49:04 +03:00
return snprintf ( buf , PAGE_SIZE , " ISP%04X \n " , ha - > pdev - > device ) ;
2005-08-27 06:09:40 +04:00
}
static ssize_t
qla2x00_isp_id_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
return snprintf ( buf , PAGE_SIZE , " %04x %04x %04x %04x \n " ,
ha - > product_id [ 0 ] , ha - > product_id [ 1 ] , ha - > product_id [ 2 ] ,
ha - > product_id [ 3 ] ) ;
}
static ssize_t
qla2x00_model_name_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
return snprintf ( buf , PAGE_SIZE , " %s \n " , ha - > model_number ) ;
}
static ssize_t
qla2x00_model_desc_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
return snprintf ( buf , PAGE_SIZE , " %s \n " ,
ha - > model_desc ? ha - > model_desc : " " ) ;
}
static ssize_t
qla2x00_pci_info_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
char pci_info [ 30 ] ;
return snprintf ( buf , PAGE_SIZE , " %s \n " ,
ha - > isp_ops . pci_info_str ( ha , pci_info ) ) ;
}
static ssize_t
qla2x00_state_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
int len = 0 ;
if ( atomic_read ( & ha - > loop_state ) = = LOOP_DOWN | |
atomic_read ( & ha - > loop_state ) = = LOOP_DEAD )
len = snprintf ( buf , PAGE_SIZE , " Link Down \n " ) ;
else if ( atomic_read ( & ha - > loop_state ) ! = LOOP_READY | |
test_bit ( ABORT_ISP_ACTIVE , & ha - > dpc_flags ) | |
test_bit ( ISP_ABORT_NEEDED , & ha - > dpc_flags ) )
len = snprintf ( buf , PAGE_SIZE , " Unknown Link State \n " ) ;
else {
len = snprintf ( buf , PAGE_SIZE , " Link Up - " ) ;
switch ( ha - > current_topology ) {
case ISP_CFG_NL :
len + = snprintf ( buf + len , PAGE_SIZE - len , " Loop \n " ) ;
break ;
case ISP_CFG_FL :
len + = snprintf ( buf + len , PAGE_SIZE - len , " FL_Port \n " ) ;
break ;
case ISP_CFG_N :
len + = snprintf ( buf + len , PAGE_SIZE - len ,
" N_Port to N_Port \n " ) ;
break ;
case ISP_CFG_F :
len + = snprintf ( buf + len , PAGE_SIZE - len , " F_Port \n " ) ;
break ;
default :
len + = snprintf ( buf + len , PAGE_SIZE - len , " Loop \n " ) ;
break ;
}
}
return len ;
}
2005-10-27 22:09:48 +04:00
static ssize_t
qla2x00_zio_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
int len = 0 ;
switch ( ha - > zio_mode ) {
case QLA_ZIO_MODE_6 :
len + = snprintf ( buf + len , PAGE_SIZE - len , " Mode 6 \n " ) ;
break ;
case QLA_ZIO_DISABLED :
len + = snprintf ( buf + len , PAGE_SIZE - len , " Disabled \n " ) ;
break ;
}
return len ;
}
static ssize_t
qla2x00_zio_store ( struct class_device * cdev , const char * buf , size_t count )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
int val = 0 ;
uint16_t zio_mode ;
2006-03-10 01:27:39 +03:00
if ( ! IS_ZIO_SUPPORTED ( ha ) )
return - ENOTSUPP ;
2005-10-27 22:09:48 +04:00
if ( sscanf ( buf , " %d " , & val ) ! = 1 )
return - EINVAL ;
2006-03-10 01:27:39 +03:00
if ( val )
2005-10-27 22:09:48 +04:00
zio_mode = QLA_ZIO_MODE_6 ;
2006-03-10 01:27:39 +03:00
else
2005-10-27 22:09:48 +04:00
zio_mode = QLA_ZIO_DISABLED ;
/* Update per-hba values and queue a reset. */
if ( zio_mode ! = QLA_ZIO_DISABLED | | ha - > zio_mode ! = QLA_ZIO_DISABLED ) {
ha - > zio_mode = zio_mode ;
set_bit ( ISP_ABORT_NEEDED , & ha - > dpc_flags ) ;
}
return strlen ( buf ) ;
}
static ssize_t
qla2x00_zio_timer_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
return snprintf ( buf , PAGE_SIZE , " %d us \n " , ha - > zio_timer * 100 ) ;
}
static ssize_t
qla2x00_zio_timer_store ( struct class_device * cdev , const char * buf ,
size_t count )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
int val = 0 ;
uint16_t zio_timer ;
if ( sscanf ( buf , " %d " , & val ) ! = 1 )
return - EINVAL ;
if ( val > 25500 | | val < 100 )
return - ERANGE ;
zio_timer = ( uint16_t ) ( val / 100 ) ;
ha - > zio_timer = zio_timer ;
return strlen ( buf ) ;
}
2006-02-01 03:05:07 +03:00
static ssize_t
qla2x00_beacon_show ( struct class_device * cdev , char * buf )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
int len = 0 ;
if ( ha - > beacon_blink_led )
len + = snprintf ( buf + len , PAGE_SIZE - len , " Enabled \n " ) ;
else
len + = snprintf ( buf + len , PAGE_SIZE - len , " Disabled \n " ) ;
return len ;
}
static ssize_t
qla2x00_beacon_store ( struct class_device * cdev , const char * buf ,
size_t count )
{
scsi_qla_host_t * ha = to_qla_host ( class_to_shost ( cdev ) ) ;
int val = 0 ;
int rval ;
if ( IS_QLA2100 ( ha ) | | IS_QLA2200 ( ha ) )
return - EPERM ;
if ( test_bit ( ABORT_ISP_ACTIVE , & ha - > dpc_flags ) ) {
qla_printk ( KERN_WARNING , ha ,
" Abort ISP active -- ignoring beacon request. \n " ) ;
return - EBUSY ;
}
if ( sscanf ( buf , " %d " , & val ) ! = 1 )
return - EINVAL ;
if ( val )
rval = ha - > isp_ops . beacon_on ( ha ) ;
else
rval = ha - > isp_ops . beacon_off ( ha ) ;
if ( rval ! = QLA_SUCCESS )
count = 0 ;
return count ;
}
2005-08-27 06:09:40 +04:00
static CLASS_DEVICE_ATTR ( driver_version , S_IRUGO , qla2x00_drvr_version_show ,
NULL ) ;
static CLASS_DEVICE_ATTR ( fw_version , S_IRUGO , qla2x00_fw_version_show , NULL ) ;
static CLASS_DEVICE_ATTR ( serial_num , S_IRUGO , qla2x00_serial_num_show , NULL ) ;
static CLASS_DEVICE_ATTR ( isp_name , S_IRUGO , qla2x00_isp_name_show , NULL ) ;
static CLASS_DEVICE_ATTR ( isp_id , S_IRUGO , qla2x00_isp_id_show , NULL ) ;
static CLASS_DEVICE_ATTR ( model_name , S_IRUGO , qla2x00_model_name_show , NULL ) ;
static CLASS_DEVICE_ATTR ( model_desc , S_IRUGO , qla2x00_model_desc_show , NULL ) ;
static CLASS_DEVICE_ATTR ( pci_info , S_IRUGO , qla2x00_pci_info_show , NULL ) ;
static CLASS_DEVICE_ATTR ( state , S_IRUGO , qla2x00_state_show , NULL ) ;
2005-10-27 22:09:48 +04:00
static CLASS_DEVICE_ATTR ( zio , S_IRUGO | S_IWUSR , qla2x00_zio_show ,
qla2x00_zio_store ) ;
static CLASS_DEVICE_ATTR ( zio_timer , S_IRUGO | S_IWUSR , qla2x00_zio_timer_show ,
qla2x00_zio_timer_store ) ;
2006-02-01 03:05:07 +03:00
static CLASS_DEVICE_ATTR ( beacon , S_IRUGO | S_IWUSR , qla2x00_beacon_show ,
qla2x00_beacon_store ) ;
2005-08-27 06:09:40 +04:00
struct class_device_attribute * qla2x00_host_attrs [ ] = {
& class_device_attr_driver_version ,
& class_device_attr_fw_version ,
& class_device_attr_serial_num ,
& class_device_attr_isp_name ,
& class_device_attr_isp_id ,
& class_device_attr_model_name ,
& class_device_attr_model_desc ,
& class_device_attr_pci_info ,
& class_device_attr_state ,
2005-10-27 22:09:48 +04:00
& class_device_attr_zio ,
& class_device_attr_zio_timer ,
2006-02-01 03:05:07 +03:00
& class_device_attr_beacon ,
2005-08-27 06:09:40 +04:00
NULL ,
} ;
2005-04-18 00:04:54 +04:00
/* Host attributes. */
static void
qla2x00_get_host_port_id ( struct Scsi_Host * shost )
{
scsi_qla_host_t * ha = to_qla_host ( shost ) ;
fc_host_port_id ( shost ) = ha - > d_id . b . domain < < 16 |
ha - > d_id . b . area < < 8 | ha - > d_id . b . al_pa ;
}
2006-02-01 03:04:51 +03:00
static void
qla2x00_get_host_speed ( struct Scsi_Host * shost )
{
scsi_qla_host_t * ha = to_qla_host ( shost ) ;
uint32_t speed = 0 ;
switch ( ha - > link_data_rate ) {
2006-10-02 23:00:43 +04:00
case PORT_SPEED_1GB :
2006-02-01 03:04:51 +03:00
speed = 1 ;
break ;
2006-10-02 23:00:43 +04:00
case PORT_SPEED_2GB :
2006-02-01 03:04:51 +03:00
speed = 2 ;
break ;
2006-10-02 23:00:43 +04:00
case PORT_SPEED_4GB :
2006-02-01 03:04:51 +03:00
speed = 4 ;
break ;
}
fc_host_speed ( shost ) = speed ;
}
2006-02-01 03:04:56 +03:00
static void
qla2x00_get_host_port_type ( struct Scsi_Host * shost )
{
scsi_qla_host_t * ha = to_qla_host ( shost ) ;
uint32_t port_type = FC_PORTTYPE_UNKNOWN ;
switch ( ha - > current_topology ) {
case ISP_CFG_NL :
port_type = FC_PORTTYPE_LPORT ;
break ;
case ISP_CFG_FL :
port_type = FC_PORTTYPE_NLPORT ;
break ;
case ISP_CFG_N :
port_type = FC_PORTTYPE_PTP ;
break ;
case ISP_CFG_F :
port_type = FC_PORTTYPE_NPORT ;
break ;
}
fc_host_port_type ( shost ) = port_type ;
}
2005-04-18 00:04:54 +04:00
static void
qla2x00_get_starget_node_name ( struct scsi_target * starget )
{
struct Scsi_Host * host = dev_to_shost ( starget - > dev . parent ) ;
scsi_qla_host_t * ha = to_qla_host ( host ) ;
2005-04-18 00:06:53 +04:00
fc_port_t * fcport ;
2005-09-01 02:21:20 +04:00
u64 node_name = 0 ;
2005-04-18 00:04:54 +04:00
2005-04-18 00:06:53 +04:00
list_for_each_entry ( fcport , & ha - > fcports , list ) {
if ( starget - > id = = fcport - > os_target_id ) {
2005-09-01 02:21:20 +04:00
node_name = wwn_to_u64 ( fcport - > node_name ) ;
2005-04-18 00:06:53 +04:00
break ;
}
}
2005-09-01 02:21:20 +04:00
fc_starget_node_name ( starget ) = node_name ;
2005-04-18 00:04:54 +04:00
}
static void
qla2x00_get_starget_port_name ( struct scsi_target * starget )
{
struct Scsi_Host * host = dev_to_shost ( starget - > dev . parent ) ;
scsi_qla_host_t * ha = to_qla_host ( host ) ;
2005-04-18 00:06:53 +04:00
fc_port_t * fcport ;
2005-09-01 02:21:20 +04:00
u64 port_name = 0 ;
2005-04-18 00:04:54 +04:00
2005-04-18 00:06:53 +04:00
list_for_each_entry ( fcport , & ha - > fcports , list ) {
if ( starget - > id = = fcport - > os_target_id ) {
2005-09-01 02:21:20 +04:00
port_name = wwn_to_u64 ( fcport - > port_name ) ;
2005-04-18 00:06:53 +04:00
break ;
}
}
2005-09-01 02:21:20 +04:00
fc_starget_port_name ( starget ) = port_name ;
2005-04-18 00:04:54 +04:00
}
static void
qla2x00_get_starget_port_id ( struct scsi_target * starget )
{
struct Scsi_Host * host = dev_to_shost ( starget - > dev . parent ) ;
scsi_qla_host_t * ha = to_qla_host ( host ) ;
2005-04-18 00:06:53 +04:00
fc_port_t * fcport ;
uint32_t port_id = ~ 0U ;
list_for_each_entry ( fcport , & ha - > fcports , list ) {
if ( starget - > id = = fcport - > os_target_id ) {
port_id = fcport - > d_id . b . domain < < 16 |
fcport - > d_id . b . area < < 8 | fcport - > d_id . b . al_pa ;
break ;
}
}
2005-04-18 00:04:54 +04:00
fc_starget_port_id ( starget ) = port_id ;
}
static void
qla2x00_get_rport_loss_tmo ( struct fc_rport * rport )
{
2005-04-18 00:06:53 +04:00
struct Scsi_Host * host = rport_to_shost ( rport ) ;
scsi_qla_host_t * ha = to_qla_host ( host ) ;
2005-04-18 00:04:54 +04:00
rport - > dev_loss_tmo = ha - > port_down_retry_count + 5 ;
}
static void
qla2x00_set_rport_loss_tmo ( struct fc_rport * rport , uint32_t timeout )
{
2005-04-18 00:06:53 +04:00
struct Scsi_Host * host = rport_to_shost ( rport ) ;
scsi_qla_host_t * ha = to_qla_host ( host ) ;
2005-04-18 00:04:54 +04:00
if ( timeout )
ha - > port_down_retry_count = timeout ;
else
ha - > port_down_retry_count = 1 ;
rport - > dev_loss_tmo = ha - > port_down_retry_count + 5 ;
}
2005-10-28 03:03:37 +04:00
static int
qla2x00_issue_lip ( struct Scsi_Host * shost )
{
scsi_qla_host_t * ha = to_qla_host ( shost ) ;
set_bit ( LOOP_RESET_NEEDED , & ha - > dpc_flags ) ;
return 0 ;
}
2006-02-01 03:05:02 +03:00
static struct fc_host_statistics *
qla2x00_get_fc_host_stats ( struct Scsi_Host * shost )
{
scsi_qla_host_t * ha = to_qla_host ( shost ) ;
int rval ;
uint16_t mb_stat [ 1 ] ;
link_stat_t stat_buf ;
struct fc_host_statistics * pfc_host_stat ;
pfc_host_stat = & ha - > fc_host_stat ;
memset ( pfc_host_stat , - 1 , sizeof ( struct fc_host_statistics ) ) ;
2006-03-10 01:27:13 +03:00
if ( IS_QLA24XX ( ha ) | | IS_QLA54XX ( ha ) ) {
2006-02-01 03:05:02 +03:00
rval = qla24xx_get_isp_stats ( ha , ( uint32_t * ) & stat_buf ,
sizeof ( stat_buf ) / 4 , mb_stat ) ;
} else {
rval = qla2x00_get_link_status ( ha , ha - > loop_id , & stat_buf ,
mb_stat ) ;
}
if ( rval ! = 0 ) {
qla_printk ( KERN_WARNING , ha ,
" Unable to retrieve host statistics (%d). \n " , mb_stat [ 0 ] ) ;
return pfc_host_stat ;
}
pfc_host_stat - > link_failure_count = stat_buf . link_fail_cnt ;
pfc_host_stat - > loss_of_sync_count = stat_buf . loss_sync_cnt ;
pfc_host_stat - > loss_of_signal_count = stat_buf . loss_sig_cnt ;
pfc_host_stat - > prim_seq_protocol_err_count = stat_buf . prim_seq_err_cnt ;
pfc_host_stat - > invalid_tx_word_count = stat_buf . inval_xmit_word_cnt ;
pfc_host_stat - > invalid_crc_count = stat_buf . inval_crc_cnt ;
return pfc_host_stat ;
}
2006-10-02 23:00:44 +04:00
static void
qla2x00_get_host_symbolic_name ( struct Scsi_Host * shost )
{
scsi_qla_host_t * ha = to_qla_host ( shost ) ;
qla2x00_get_sym_node_name ( ha , fc_host_symbolic_name ( shost ) ) ;
}
2006-10-02 23:00:45 +04:00
static void
qla2x00_set_host_system_hostname ( struct Scsi_Host * shost )
{
scsi_qla_host_t * ha = to_qla_host ( shost ) ;
set_bit ( REGISTER_FDMI_NEEDED , & ha - > dpc_flags ) ;
}
2005-04-22 00:13:36 +04:00
struct fc_function_template qla2xxx_transport_functions = {
2005-04-18 00:04:54 +04:00
. show_host_node_name = 1 ,
. show_host_port_name = 1 ,
2005-08-27 06:08:10 +04:00
. show_host_supported_classes = 1 ,
2005-04-18 00:04:54 +04:00
. get_host_port_id = qla2x00_get_host_port_id ,
. show_host_port_id = 1 ,
2006-02-01 03:04:51 +03:00
. get_host_speed = qla2x00_get_host_speed ,
. show_host_speed = 1 ,
2006-02-01 03:04:56 +03:00
. get_host_port_type = qla2x00_get_host_port_type ,
. show_host_port_type = 1 ,
2006-10-02 23:00:44 +04:00
. get_host_symbolic_name = qla2x00_get_host_symbolic_name ,
. show_host_symbolic_name = 1 ,
2006-10-02 23:00:45 +04:00
. set_host_system_hostname = qla2x00_set_host_system_hostname ,
. show_host_system_hostname = 1 ,
2005-04-18 00:04:54 +04:00
2005-04-18 00:06:53 +04:00
. dd_fcrport_size = sizeof ( struct fc_port * ) ,
2005-08-27 06:08:10 +04:00
. show_rport_supported_classes = 1 ,
2005-04-18 00:04:54 +04:00
. get_starget_node_name = qla2x00_get_starget_node_name ,
. show_starget_node_name = 1 ,
. get_starget_port_name = qla2x00_get_starget_port_name ,
. show_starget_port_name = 1 ,
. get_starget_port_id = qla2x00_get_starget_port_id ,
. show_starget_port_id = 1 ,
. get_rport_dev_loss_tmo = qla2x00_get_rport_loss_tmo ,
. set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo ,
. show_rport_dev_loss_tmo = 1 ,
2005-10-28 03:03:37 +04:00
. issue_fc_host_lip = qla2x00_issue_lip ,
2006-02-01 03:05:02 +03:00
. get_fc_host_stats = qla2x00_get_fc_host_stats ,
2005-04-18 00:04:54 +04:00
} ;
void
qla2x00_init_host_attr ( scsi_qla_host_t * ha )
{
2006-01-14 04:04:49 +03:00
fc_host_node_name ( ha - > host ) = wwn_to_u64 ( ha - > node_name ) ;
fc_host_port_name ( ha - > host ) = wwn_to_u64 ( ha - > port_name ) ;
2005-08-27 06:08:10 +04:00
fc_host_supported_classes ( ha - > host ) = FC_COS_CLASS3 ;
2005-04-18 00:04:54 +04:00
}