RE: [PATCH] pm8001: enhance firmware event log retrieval

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> The pm8001 driver event log currently only reports the current firmware
event
> log index and the first entry (if log has not wrapped). The enclosed patch
> enhances the event log retrieved to sequentially return all un-retrieved
> entries until hitting the last, from then on reporting the last entry. The
> format has been changed in a parseable fashion reporting some of the
interpreted
> fields; the entry sequence number can be used to determine the boundary
> condition when the last entry is retrieved.
> 
> Formerly, when the logging level is changed at runtime, it does not
transmit
> the updated level to the firmware. We also added a set of insmod
parameters
> so that the logging level may be set at initialization time.
> 
[Jack Wang] Patch is welcome.
> As this disrupts backward compatibility, we look forward to community
comments.
> Also, once an earlier log entry is retrieved, it is the expectation of the
> logging/forensic program(?) to record them as they can not be retrieved
again.
> Please keep in mind that the first event log entry as previously reported
by
> the existing code becomes somewhat moot if new entries form.
> 
[Jack Wang] I wonder what user need this function? How do you test this
function?

> Signed-off-by: mark_salyzyn@xxxxxxxxxxx
> Cc: jack_wang@xxxxxxxxx
> Cc: JBottomley@xxxxxxxxxxxxx
> Cc: crystal_yu@xxxxxxxxx
> Cc: john_gong@xxxxxxxxx
> Cc: lindar_liu <lindar_liu@xxxxxxxxx>

[Jack Wang] 
Acked-by: Jack Wang <jack_wang@xxxxxxxxx>
Thanks.

> 
> diff --git a/drivers/scsi/pm8001/pm8001_ctl.c
> b/drivers/scsi/pm8001/pm8001_ctl.c
> index 45bc197..3fe3d93 100644
> --- a/drivers/scsi/pm8001/pm8001_ctl.c
> +++ b/drivers/scsi/pm8001/pm8001_ctl.c
> @@ -228,46 +228,140 @@ static ssize_t
pm8001_ctl_logging_level_store(struct
> device *cdev,
>  		return -EINVAL;
> 
>  	pm8001_ha->logging_level = val;
> +	pm8001_update_main_config_table(pm8001_ha);
>  	return strlen(buf);
>  }
> 
>  static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR,
>  	pm8001_ctl_logging_level_show, pm8001_ctl_logging_level_store);
> +
>  /**
> - * pm8001_ctl_aap_log_show - aap1 event log
> + * pm8001_readlog - generic routine to read a single event log entry
> + * @header: a pointer to the event log base header
> + * @entry: a pointer to copy the latest event log into
> + * @consumer_index: a current local index pointing to the last oldest
entry
> + *                  retrieved. Automatically incremented and wrapped.
> + * @return: A copied entry content and a status. Status return of zero
means
> + *          more entries available, and the consumer index is incremented
and
> + *          wrapped. A positive status return means last entry, the
consumer
> + *          index may be incremented depending of approached or at the
last
> + *          entry. Status can also return a negative error code. It is
the
> + *          responsibility of the caller to confirm the validity of the
copied
> + *          event information.
> + */
> +int pm8001_readlog(
> +	struct eventlog_header *header,
> +	struct eventlog_entry *entry,
> +	u32 *consumer_index)
> +{
> +	unsigned maximum_index;
> +	unsigned producer_index;
> +
> +	/* Validity of header */
> +	if ((header->offset != sizeof(*header)) ||
> +	    (header->entry_size != sizeof(*entry)) ||
> +	    ((header->signature != EVENTLOG_HEADER_SIGNATURE_AAP1) &&
> +	     (header->signature != EVENTLOG_HEADER_SIGNATURE_IOP)))
> +		return -EINVAL;
> +	/* Validity of hardware indexii */
> +	maximum_index = header->size / sizeof(*entry);
> +	if ((maximum_index <= header->producer_index) ||
> +	    (maximum_index <= header->consumer_index))
> +		return -EINVAL;
> +	producer_index = header->producer_index;
> +	if (producer_index == 0)
> +		producer_index = maximum_index - 1;
> +	else
> +		--producer_index;
> +	/* Validity of current consumer index */
> +	if (((producer_index < header->consumer_index) ?
> +	     ((producer_index < *consumer_index) &&
> +	      (*consumer_index < header->consumer_index)) :
> +	     ((producer_index < *consumer_index) ||
> +	      (*consumer_index < header->consumer_index))) ||
> +	    (*consumer_index >= maximum_index))
> +		*consumer_index = header->consumer_index;
> +	*entry = ((struct eventlog_entry *)(header + 1))[*consumer_index];
> +	if (*consumer_index != producer_index) {
> +		++(*consumer_index);
> +		if (*consumer_index >= maximum_index)
> +			*consumer_index = 0;
> +		/* More entries? */
> +		return *consumer_index == producer_index;
> +	}
> +	return 2; /* Already at Last Entry */
> +}
> +
> +/**
> + * pm8001_validlog - generic routine to validate a single event log entry
> + * @entry: a pointer to the event log entry
> + * @return: zero if not valid
> + */
> +static inline int pm8001_validlog(struct eventlog_entry *entry)
> +{
> +	return ((entry->size <= (sizeof(entry->log) /
sizeof(entry->log[0]))) &&
> +		((entry->timestamp_upper != 0) ||
> +		 (entry->timestamp_lower != 0)));
> +}
> +
> +/**
> + * pm8001_ctl_log_show - event log
>   * @cdev: pointer to embedded class device
>   * @buf: the buffer returned
> + * @ind: The region index (AAP1 or IOP)
>   *
>   * A sysfs 'read-only' shost attribute.
>   */
> -static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
> -	struct device_attribute *attr, char *buf)
> +static ssize_t pm8001_ctl_log_show(struct device *cdev, char *buf, int
ind)
>  {
>  	struct Scsi_Host *shost = class_to_shost(cdev);
>  	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
>  	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
> +	struct eventlog_entry entry;
> +	char *str = buf;
>  	int i;
> -#define AAP1_MEMMAP(r, c) \
> -	(*(u32 *)((u8*)pm8001_ha->memoryMap.region[AAP1].virt_ptr + (r) * 32
\
> -	+ (c)))
> 
> -	char *str = buf;
> -	int max = 2;
> -	for (i = 0; i < max; i++) {
> -		str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x
0x%08x"
> -			       "0x%08x 0x%08x\n",
> -			       AAP1_MEMMAP(i, 0),
> -			       AAP1_MEMMAP(i, 4),
> -			       AAP1_MEMMAP(i, 8),
> -			       AAP1_MEMMAP(i, 12),
> -			       AAP1_MEMMAP(i, 16),
> -			       AAP1_MEMMAP(i, 20),
> -			       AAP1_MEMMAP(i, 24),
> -			       AAP1_MEMMAP(i, 28));
> +	memset(&entry, 0, sizeof(entry));
> +	do {
> +		i = pm8001_readlog(
> +			(struct eventlog_header *)(
> +				pm8001_ha->memoryMap.region[ind].virt_ptr),
> +			&entry,
> +			(ind == AAP1) ?
> +				&pm8001_ha->aap1_consumer :
> +				&pm8001_ha->iop_consumer);
> +	} while ((i == 0) && !pm8001_validlog(&entry));
> +	if ((i >= 0) && pm8001_validlog(&entry)) {
> +		u32 *lp;
> +		unsigned long long timestamp =
> +			(((unsigned long long)entry.timestamp_upper) << 32)
|
> +			entry.timestamp_lower;
> +		str += snprintf(str, PAGE_SIZE - (str - buf),
> +			"%u %llu.%09llu %u",
> +			entry.severity,
> +			timestamp / (1000000000 / 8),
> +			(timestamp % (1000000000 / 8)) * 8,
> +			entry.sequence);
> +		for (lp = entry.log, i = entry.size; i > 0; --i)
> +			str += snprintf(str, PAGE_SIZE - (str - buf),
> +				" 0x%08x", *(lp++));
> +		str += snprintf(str, PAGE_SIZE - (str - buf), "\n");
>  	}
> -
>  	return str - buf;
>  }
> +
> +/**
> + * pm8001_ctl_aap_log_show - aap1 event log
> + * @cdev: pointer to embedded class device
> + * @buf: the buffer returned
> + *
> + * A sysfs 'read-only' shost attribute.
> + */
> +static ssize_t pm8001_ctl_aap_log_show(struct device *cdev,
> +	struct device_attribute *attr, char *buf)
> +{
> +	return pm8001_ctl_log_show(cdev, buf, AAP1);
> +}
>  static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL);
>  /**
>   * pm8001_ctl_aap_log_show - IOP event log
> @@ -279,29 +373,7 @@ static DEVICE_ATTR(aap_log, S_IRUGO,
> pm8001_ctl_aap_log_show, NULL);
>  static ssize_t pm8001_ctl_iop_log_show(struct device *cdev,
>  	struct device_attribute *attr, char *buf)
>  {
> -	struct Scsi_Host *shost = class_to_shost(cdev);
> -	struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost);
> -	struct pm8001_hba_info *pm8001_ha = sha->lldd_ha;
> -#define IOP_MEMMAP(r, c) \
> -	(*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32
\
> -	+ (c)))
> -	int i;
> -	char *str = buf;
> -	int max = 2;
> -	for (i = 0; i < max; i++) {
> -		str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x
0x%08x"
> -			       "0x%08x 0x%08x\n",
> -			       IOP_MEMMAP(i, 0),
> -			       IOP_MEMMAP(i, 4),
> -			       IOP_MEMMAP(i, 8),
> -			       IOP_MEMMAP(i, 12),
> -			       IOP_MEMMAP(i, 16),
> -			       IOP_MEMMAP(i, 20),
> -			       IOP_MEMMAP(i, 24),
> -			       IOP_MEMMAP(i, 28));
> -	}
> -
> -	return str - buf;
> +	return pm8001_ctl_log_show(cdev, buf, IOP);
>  }
>  static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL);
> 
> diff --git a/drivers/scsi/pm8001/pm8001_hwi.c
> b/drivers/scsi/pm8001/pm8001_hwi.c
> index b7b92f7..b3bd781 100644
> --- a/drivers/scsi/pm8001/pm8001_hwi.c
> +++ b/drivers/scsi/pm8001/pm8001_hwi.c
> @@ -250,8 +250,8 @@ init_default_table_values(struct pm8001_hba_info
> *pm8001_ha)
>   * update_main_config_table - update the main default table to the HBA.
>   * @pm8001_ha: our hba card information
>   */
> -static void __devinit
> -update_main_config_table(struct pm8001_hba_info *pm8001_ha)
> +void
> +pm8001_update_main_config_table(struct pm8001_hba_info *pm8001_ha)
>  {
>  	void __iomem *address = pm8001_ha->main_cfg_tbl_addr;
>  	pm8001_mw32(address, 0x24,
> @@ -603,7 +603,7 @@ static int __devinit pm8001_chip_init(struct
> pm8001_hba_info *pm8001_ha)
>  	read_inbnd_queue_table(pm8001_ha);
>  	read_outbnd_queue_table(pm8001_ha);
>  	/* update main config table ,inbound table and outbound table */
> -	update_main_config_table(pm8001_ha);
> +	pm8001_update_main_config_table(pm8001_ha);
>  	update_inbnd_queue_table(pm8001_ha, 0);
>  	update_outbnd_queue_table(pm8001_ha, 0);
>  	mpi_set_phys_g3_with_ssc(pm8001_ha, 0);
> diff --git a/drivers/scsi/pm8001/pm8001_init.c
> b/drivers/scsi/pm8001/pm8001_init.c
> index c21a216..c638da4 100644
> --- a/drivers/scsi/pm8001/pm8001_init.c
> +++ b/drivers/scsi/pm8001/pm8001_init.c
> @@ -48,6 +48,8 @@ static const struct pm8001_chip_info pm8001_chips[] = {
>  	[chip_8001] = {  8, &pm8001_8001_dispatch,},
>  };
>  static int pm8001_id;
> +static int pm8001_logging_level = PM8001_FAIL_LOGGING;
> +static int pm8001_logging_size = PM8001_EVENT_LOG_SIZE;
> 
>  LIST_HEAD(hba_list);
> 
> @@ -212,16 +214,19 @@ static int __devinit pm8001_alloc(struct
pm8001_hba_info
> *pm8001_ha)
>  	pm8001_ha->tags = kzalloc(PM8001_MAX_CCB, GFP_KERNEL);
>  	if (!pm8001_ha->tags)
>  		goto err_out;
> +	pm8001_logging_size = ((pm8001_logging_size + 31) / 32) * 32;
> +	if (pm8001_logging_size < 64)
> +		pm8001_logging_size = 64;
>  	/* MPI Memory region 1 for AAP Event Log for fw */
>  	pm8001_ha->memoryMap.region[AAP1].num_elements = 1;
> -	pm8001_ha->memoryMap.region[AAP1].element_size =
> PM8001_EVENT_LOG_SIZE;
> -	pm8001_ha->memoryMap.region[AAP1].total_len = PM8001_EVENT_LOG_SIZE;
> +	pm8001_ha->memoryMap.region[AAP1].element_size =
pm8001_logging_size;
> +	pm8001_ha->memoryMap.region[AAP1].total_len = pm8001_logging_size;
>  	pm8001_ha->memoryMap.region[AAP1].alignment = 32;
> 
>  	/* MPI Memory region 2 for IOP Event Log for fw */
>  	pm8001_ha->memoryMap.region[IOP].num_elements = 1;
> -	pm8001_ha->memoryMap.region[IOP].element_size =
PM8001_EVENT_LOG_SIZE;
> -	pm8001_ha->memoryMap.region[IOP].total_len = PM8001_EVENT_LOG_SIZE;
> +	pm8001_ha->memoryMap.region[IOP].element_size = pm8001_logging_size;
> +	pm8001_ha->memoryMap.region[IOP].total_len = pm8001_logging_size;
>  	pm8001_ha->memoryMap.region[IOP].alignment = 32;
> 
>  	/* MPI Memory region 3 for consumer Index of inbound queues */
> @@ -242,7 +247,7 @@ static int __devinit pm8001_alloc(struct
pm8001_hba_info
> *pm8001_ha)
>  	pm8001_ha->memoryMap.region[IB].total_len = 256 * 64;
>  	pm8001_ha->memoryMap.region[IB].alignment = 64;
> 
> -	/* MPI Memory region 6 inbound queues */
> +	/* MPI Memory region 6 outbound queues */
>  	pm8001_ha->memoryMap.region[OB].num_elements = 256;
>  	pm8001_ha->memoryMap.region[OB].element_size = 64;
>  	pm8001_ha->memoryMap.region[OB].total_len = 256 * 64;
> @@ -381,7 +386,7 @@ pm8001_pci_alloc(struct pci_dev *pdev, u32 chip_id,
struct
> Scsi_Host *shost)
>  	pm8001_ha->sas = sha;
>  	pm8001_ha->shost = shost;
>  	pm8001_ha->id = pm8001_id++;
> -	pm8001_ha->logging_level = 0x01;
> +	pm8001_ha->logging_level = pm8001_logging_level;
>  	sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id);
>  #ifdef PM8001_USE_TASKLET
>  	tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet,
> @@ -614,8 +619,8 @@ intx:
>   * @ent: pci device id
>   *
>   * This function is the main initialization function, when register a new
> - * pci driver it is invoked, all struct an hardware initilization should
be
> done
> - * here, also, register interrupt
> + * pci driver it is invoked, all struct and hardware initialization
should
> be
> + * done here, also, register interrupt
>   */
>  static int __devinit pm8001_pci_probe(struct pci_dev *pdev,
>  	const struct pci_device_id *ent)
> @@ -899,6 +904,9 @@ static void __exit pm8001_exit(void)
>  	destroy_workqueue(pm8001_wq);
>  }
> 
> +module_param(pm8001_logging_level, int, 0);
> +module_param_named(logging_size, pm8001_logging_size, int,
> S_IRUGO|S_IWUSR);
> +MODULE_PARM_DESC(logging_size, "Event logging buffer size");
>  module_init(pm8001_init);
>  module_exit(pm8001_exit);
> 
> diff --git a/drivers/scsi/pm8001/pm8001_sas.h
> b/drivers/scsi/pm8001/pm8001_sas.h
> index 93959fe..84d3170 100644
> --- a/drivers/scsi/pm8001/pm8001_sas.h
> +++ b/drivers/scsi/pm8001/pm8001_sas.h
> @@ -336,6 +336,29 @@ struct outbound_queue_table {
>  	__le32			producer_index;
>  	u32			consumer_idx;
>  };
> +struct eventlog_header {
> +	__le32			signature;
> +#define EVENTLOG_HEADER_SIGNATURE_AAP1 0x1234AAAA
> +#define EVENTLOG_HEADER_SIGNATURE_IOP 0x5678CCCC
> +	__le32			offset; /* sizeof(eventlog_header) */
> +	u32			reserved1;
> +	__le32			size;
> +	u32			reserved2;
> +	__le32			consumer_index;
> +	__le32			producer_index;
> +	__le32			entry_size;
> +};
> +struct eventlog_entry {
> +	u8			size:3;
> +	u8			reserved1:5;
> +	u8			reserved2[2];
> +	u8			reserved:4;
> +	u8			severity:4;
> +	__le32			timestamp_upper;
> +	__le32			timestamp_lower;
> +	__le32			sequence;
> +	__le32			log[4];
> +};
>  struct pm8001_hba_memspace {
>  	void __iomem  		*memvirtaddr;
>  	u64			membase;
> @@ -383,6 +406,9 @@ struct pm8001_hba_info {
>  	u32			logging_level;
>  	u32			fw_status;
>  	const struct firmware 	*fw_image;
> +	/* Local consumer indexes in support of sysfs event log node */
> +	u32			aap1_consumer;
> +	u32			iop_consumer;
>  };
> 
>  struct pm8001_work {
> @@ -488,6 +514,11 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void
> **virt_addr,
>  	dma_addr_t *pphys_addr, u32 *pphys_addr_hi, u32 *pphys_addr_lo,
>  	u32 mem_size, u32 align);
> 
> +void pm8001_update_main_config_table(struct pm8001_hba_info *pm8001_ha);
> +int pm8001_readlog(
> +	struct eventlog_header *header,
> +	struct eventlog_entry *entry,
> +	u32 *consumer_index);
> 
>  /* ctl shared API */
>  extern struct device_attribute *pm8001_host_attrs[];
> 
> ______________________________________________________________________
> This email may contain privileged or confidential information, which
should
> only be used for the purpose for which it was sent by Xyratex. No further
rights
> or licenses are granted to use such information. If you are not the
intended
> recipient of this message, please notify the sender by return and delete
it.
> You may not use, copy, disclose or rely on the information contained in
it.
> 
> Internet email is susceptible to data corruption, interception and
> unauthorised amendment for which Xyratex does not accept liability. While
we
> have taken reasonable precautions to ensure that this email is free of
viruses,
> Xyratex does not accept liability for the presence of any computer viruses
in
> this email, nor for any losses caused as a result of viruses.
> 
> Xyratex Technology Limited (03134912), Registered in England & Wales,
> Registered Office, Langstone Road, Havant, Hampshire, PO9 1SA.
> 
> The Xyratex group of companies also includes, Xyratex Ltd, registered in
> Bermuda, Xyratex International Inc, registered in California, Xyratex
> (Malaysia) Sdn Bhd registered in Malaysia, Xyratex Technology (Wuxi) Co
Ltd
> registered in The People's Republic of China and Xyratex Japan Limited
> registered in Japan.
> ______________________________________________________________________
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux