Skip to contentSkip to conversation

pm80xx : Updates for the driver version 0.1.39.

PATCH Superseded Deepak Ukey 5 participants 38 messages Jan 17, 2020 – Mar 16, 2020

Subsystems (2)

v2 of 7 Superseded Latest is v7 →

lore
Share & tools
lore
#0 lore raw

v2 cover pm80xx : Updates for the driver version 0.1.39.

From: Deepak Ukey <[email protected]>

This patch set includes some bug fixes and features for pm80xx driver.

Changes from V1:
For "Increase request sg length" patch.
- Fix the compilation warning generated on xtensa architecture.
For "Support for char device" patch.
- Modified the description of patch.
For "IOCTL functionality to get phy profile." patch.
- Split the patch in two different patches.
IOCTL functionality to get phy status and
IOCTL functionality to get phy error.
For "IOCTL functionality for SGPIO" patch.
- Fixed the compilation warning generated on x86_64 architecture.
For "sysfs attribute for non fatal dump" patch.
- Modified the description of patch.
For "IOCTL functionality for TWI device" patch.
- Modified the description of patch.

Deepak Ukey (5):
pm80xx : Support for char device.
pm80xx : IOCTL functionality for GPIO.
pm80xx : IOCTL functionality for SGPIO.
pm80xx : sysfs attribute for non fatal dump.
pm80xx : IOCTL functionality for TWI device.

Peter Chang (2):
pm80xx : Increase request sg length. pm80xx : Cleanup initialization loading fail path.

Vikram Auradkar (1):
pm80xx : Deal with kexec reboots.

Viswas G (4):
pm80xx : sysfs attribute for number of phys.
pm80xx : IOCTL functionality to get phy status.
pm80xx : IOCTL functionality to get phy error.
pm80xx : Introduce read and write length for IOCTL payload structure.

yuuzheng (1):
pm80xx : Free the tag when mpi_set_phy_profile_resp is received.

 drivers/scsi/pm8001/pm8001_ctl.c  | 662 +++++++++++++++++++++++++++++++++++++-
 drivers/scsi/pm8001/pm8001_ctl.h  | 185 +++++++++++
 drivers/scsi/pm8001/pm8001_defs.h |   5 +-
 drivers/scsi/pm8001/pm8001_hwi.c  | 303 +++++++++++++++--
 drivers/scsi/pm8001/pm8001_hwi.h  |  18 ++
 drivers/scsi/pm8001/pm8001_init.c | 104 ++++--
 drivers/scsi/pm8001/pm8001_sas.c  |  37 +++
 drivers/scsi/pm8001/pm8001_sas.h  |  70 +++-
 drivers/scsi/pm8001/pm80xx_hwi.c  | 390 +++++++++++++++++++++-
 drivers/scsi/pm8001/pm80xx_hwi.h  |  55 ++++
 10 files changed, 1767 insertions(+), 62 deletions(-)
Signature · 1 line
2.16.3
#1 lore raw

PATCH v2 1/13 pm80xx : Increase request sg length.

From: Peter Chang <[email protected]>

Increasing the per-request size maximum (max_sectors_kb) runs into the per-device dma scatter gather list limit (max_segments) for users of the io vector system calls (eg, readv and writev). This is because the kernel combines io vectors into dma segments when possible, but it doesn't work for our user because the vectors in the buffer cache get scrambled.
This change bumps the advertised max scatter gather length to 528 to cover 2M w/ x86's 4k pages and some extra for the user checksum. It trims the size of some of the tables we don't care about and exposes all of the command slots upstream to the scsi layer

---
 drivers/scsi/pm8001/pm8001_defs.h | 5 +++--
 drivers/scsi/pm8001/pm8001_init.c | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/scsi/pm8001/pm8001_defs.h +3 -2
index 48e0624ecc68..1c7f15fd69ce 100644
@@ -75,7 +75,7 @@ enum port_type {
 };
 
 /* driver compile-time configuration */
-#define	PM8001_MAX_CCB		 512	/* max ccbs supported */
+#define	PM8001_MAX_CCB		 256	/* max ccbs supported */
 #define PM8001_MPI_QUEUE         1024   /* maximum mpi queue entries */
 #define	PM8001_MAX_INB_NUM	 1
 #define	PM8001_MAX_OUTB_NUM	 1
@@ -99,7 +99,8 @@ enum port_type {
 #define OB			(CI + PM8001_MAX_SPCV_INB_NUM)
 #define PI			(OB + PM8001_MAX_SPCV_OUTB_NUM)
 #define USI_MAX_MEMCNT		(PI + PM8001_MAX_SPCV_OUTB_NUM)
-#define PM8001_MAX_DMA_SG	SG_ALL
+#define	CONFIG_SCSI_PM8001_MAX_DMA_SG	528
+#define PM8001_MAX_DMA_SG	CONFIG_SCSI_PM8001_MAX_DMA_SG
 enum memory_region_num {
 	AAP1 = 0x0, /* application acceleration processor */
 	IOP,	    /* IO processor */
drivers/scsi/pm8001/pm8001_init.c +1 -1
index ff618ad80ebd..3f1e755c52c6 100644
@@ -95,7 +95,7 @@ static struct scsi_host_template pm8001_sht = {
 	.bios_param		= sas_bios_param,
 	.can_queue		= 1,
 	.this_id		= -1,
-	.sg_tablesize		= SG_ALL,
+	.sg_tablesize		= PM8001_MAX_DMA_SG,
 	.max_sectors		= SCSI_DEFAULT_MAX_SECTORS,
 	.eh_device_reset_handler = sas_eh_device_reset_handler,
 	.eh_target_reset_handler = sas_eh_target_reset_handler,
Signature · 1 line
2.16.3
maintainer
#2 lore raw

Re: [PATCH V2 01/13] pm80xx : Increase request sg length.

Quoted 29 lines · Deepak Ukey

From: Peter Chang <[email protected]>

Increasing the per-request size maximum (max_sectors_kb) runs into the per-device dma scatter gather list limit (max_segments) for users of the io vector system calls (eg, readv and writev). This is because the kernel combines io vectors into dma segments when possible, but it doesn't work for our user because the vectors in the buffer cache get scrambled.
This change bumps the advertised max scatter gather length to 528 to cover 2M w/ x86's 4k pages and some extra for the user checksum. It trims the size of some of the tables we don't care about and exposes all of the command slots upstream to the scsi layer

---
 drivers/scsi/pm8001/pm8001_defs.h | 5 +++--
 drivers/scsi/pm8001/pm8001_init.c | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/scsi/pm8001/pm8001_defs.h +0 -0
index 48e0624ecc68..1c7f15fd69ce 100644

drivers/scsi/pm8001/pm8001_defs.h enum port_type { · line 78

Quoted 5 lines
drivers/scsi/pm8001/pm8001_defs.h +1 -1
@@ -75,7 +75,7 @@ enum port_type {
 };
 
 /* driver compile-time configuration */
-#define        PM8001_MAX_CCB           512    /* max ccbs supported */
+#define        PM8001_MAX_CCB           256    /* max ccbs supported */

Hi Deepack,

Why do you reduce PM8001_MAX_CCB?

The patch itself looks fine.

#3 lore raw

RE: [PATCH V2 01/13] pm80xx : Increase request sg length.

Quoted 30 lines · Deepak Ukey

From: Peter Chang <[email protected]>

Increasing the per-request size maximum (max_sectors_kb) runs into the per-device dma scatter gather list limit (max_segments) for users of the io vector system calls (eg, readv and writev). This is because the kernel combines io vectors into dma segments when possible, but it doesn't work for our user because the vectors in the buffer cache get scrambled.
This change bumps the advertised max scatter gather length to 528 to cover 2M w/ x86's 4k pages and some extra for the user checksum. It trims the size of some of the tables we don't care about and exposes all of the command slots upstream to the scsi layer

---
 drivers/scsi/pm8001/pm8001_defs.h | 5 +++--  
drivers/scsi/pm8001/pm8001_init.c | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/scsi/pm8001/pm8001_defs.h +0 -0
index 48e0624ecc68..1c7f15fd69ce 100644

drivers/scsi/pm8001/pm8001_defs.h enum port_type { · line 78

Quoted 5 lines
drivers/scsi/pm8001/pm8001_defs.h +1 -1
@@ -75,7 +75,7 @@ enum port_type {
 };
 
 /* driver compile-time configuration */
-#define        PM8001_MAX_CCB           512    /* max ccbs supported */
+#define        PM8001_MAX_CCB           256    /* max ccbs supported */

Hi Deepack,

Why do you reduce PM8001_MAX_CCB?
--- PM8001 driver has a memory limit in the machine. If we increase the sg length, we need to trade-off it by decreasing PM8001_MAX_CCB. PM8001_MAX_CCB = 256 does not have any influence on normal use.

The patch itself looks fine.

maintainer
#4 lore raw

Re: [PATCH V2 01/13] pm80xx : Increase request sg length.

Quoted 34 lines · On Fri, Jan 17, 2020 at 4:50 PM <[email protected]> wrote:
Quoted 32 lines · Deepak Ukey

From: Peter Chang <[email protected]>

Increasing the per-request size maximum (max_sectors_kb) runs into the per-device dma scatter gather list limit (max_segments) for users of the io vector system calls (eg, readv and writev). This is because the kernel combines io vectors into dma segments when possible, but it doesn't work for our user because the vectors in the buffer cache get scrambled.
This change bumps the advertised max scatter gather length to 528 to cover 2M w/ x86's 4k pages and some extra for the user checksum. It trims the size of some of the tables we don't care about and exposes all of the command slots upstream to the scsi layer

---
 drivers/scsi/pm8001/pm8001_defs.h | 5 +++--
drivers/scsi/pm8001/pm8001_init.c | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/scsi/pm8001/pm8001_defs.h +0 -0
index 48e0624ecc68..1c7f15fd69ce 100644
@@ -75,7 +75,7 @@ enum port_type {
 };
 
Quoted 7 lines

drivers/scsi/pm8001/pm8001_defs.h enum port_type { · line 78

Quoted 3 lines
drivers/scsi/pm8001/pm8001_defs.h +1 -1
 /* driver compile-time configuration */
-#define        PM8001_MAX_CCB           512    /* max ccbs supported */
+#define        PM8001_MAX_CCB           256    /* max ccbs supported */

Hi Deepack,

Why do you reduce PM8001_MAX_CCB?
--- PM8001 driver has a memory limit in the machine.

which limit, do you see allocation failure from kernel? Thanks

#5 lore raw

RE: [PATCH V2 01/13] pm80xx : Increase request sg length.

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 34 lines · On Fri, Jan 17, 2020 at 4:50 PM <[email protected]> wrote:
Quoted 32 lines · Deepak Ukey

From: Peter Chang <[email protected]>

Increasing the per-request size maximum (max_sectors_kb) runs into the per-device dma scatter gather list limit (max_segments) for users of the io vector system calls (eg, readv and writev). This is because the kernel combines io vectors into dma segments when possible, but it doesn't work for our user because the vectors in the buffer cache get scrambled.
This change bumps the advertised max scatter gather length to 528 to cover 2M w/ x86's 4k pages and some extra for the user checksum. It trims the size of some of the tables we don't care about and exposes all of the command slots upstream to the scsi layer

---
 drivers/scsi/pm8001/pm8001_defs.h | 5 +++-- 
drivers/scsi/pm8001/pm8001_init.c | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/scsi/pm8001/pm8001_defs.h +0 -0
index 48e0624ecc68..1c7f15fd69ce 100644
@@ -75,7 +75,7 @@ enum port_type {
 };
 
Quoted 7 lines

drivers/scsi/pm8001/pm8001_defs.h enum port_type { · line 78

Quoted 3 lines
drivers/scsi/pm8001/pm8001_defs.h +1 -1
 /* driver compile-time configuration */
-#define        PM8001_MAX_CCB           512    /* max ccbs supported */
+#define        PM8001_MAX_CCB           256    /* max ccbs supported */

Hi Deepack,

Why do you reduce PM8001_MAX_CCB?
--- PM8001 driver has a memory limit in the machine.

which limit, do you see allocation failure from kernel?
-- I think it depends on machine's capability. For our machines, PM8001_MAX_CCB = 512 caused kernel installation failure. I saw it when I was debugging ncq feature Thanks

maintainer
#6 lore raw

Re: [PATCH V2 01/13] pm80xx : Increase request sg length.

Quoted 44 lines · On Mon, Jan 20, 2020 at 5:20 AM <[email protected]> wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 39 lines · On Fri, Jan 17, 2020 at 4:50 PM <[email protected]> wrote:
Quoted 30 lines · Deepak Ukey

From: Peter Chang <[email protected]>

Increasing the per-request size maximum (max_sectors_kb) runs into the per-device dma scatter gather list limit (max_segments) for users of the io vector system calls (eg, readv and writev). This is because the kernel combines io vectors into dma segments when possible, but it doesn't work for our user because the vectors in the buffer cache get scrambled.
This change bumps the advertised max scatter gather length to 528 to cover 2M w/ x86's 4k pages and some extra for the user checksum. It trims the size of some of the tables we don't care about and exposes all of the command slots upstream to the scsi layer

---
 drivers/scsi/pm8001/pm8001_defs.h | 5 +++--
drivers/scsi/pm8001/pm8001_init.c | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/scsi/pm8001/pm8001_defs.h +0 -0
index 48e0624ecc68..1c7f15fd69ce 100644

drivers/scsi/pm8001/pm8001_defs.h enum port_type { · line 78

Quoted 5 lines
drivers/scsi/pm8001/pm8001_defs.h +1 -1
@@ -75,7 +75,7 @@ enum port_type {
 };
 
 /* driver compile-time configuration */
-#define        PM8001_MAX_CCB           512    /* max ccbs supported */
+#define        PM8001_MAX_CCB           256    /* max ccbs supported */

Hi Deepack,

Quoted 5 lines
Quoted 2 lines

Why do you reduce PM8001_MAX_CCB?
--- PM8001 driver has a memory limit in the machine.

which limit, do you see allocation failure from kernel?
-- I think it depends on machine's capability. For our machines, PM8001_MAX_CCB = 512 caused kernel installation failure. I saw it when I was debugging ncq feature Thanks

Ok, would be helpful to put this info to commit message.

Thanks

#7 lore raw

RE: [PATCH V2 01/13] pm80xx : Increase request sg length.

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 44 lines · On Mon, Jan 20, 2020 at 5:20 AM <[email protected]> wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 38 lines · On Fri, Jan 17, 2020 at 4:50 PM <[email protected]> wrote:
Quoted 30 lines · Deepak Ukey

From: Peter Chang <[email protected]>

Increasing the per-request size maximum (max_sectors_kb) runs into the per-device dma scatter gather list limit (max_segments) for users of the io vector system calls (eg, readv and writev). This is because the kernel combines io vectors into dma segments when possible, but it doesn't work for our user because the vectors in the buffer cache get scrambled.
This change bumps the advertised max scatter gather length to 528 to cover 2M w/ x86's 4k pages and some extra for the user checksum. It trims the size of some of the tables we don't care about and exposes all of the command slots upstream to the scsi layer

---
 drivers/scsi/pm8001/pm8001_defs.h | 5 +++-- 
drivers/scsi/pm8001/pm8001_init.c | 2 +-
 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/scsi/pm8001/pm8001_defs.h +0 -0
index 48e0624ecc68..1c7f15fd69ce 100644

drivers/scsi/pm8001/pm8001_defs.h enum port_type { }; · line 77

Quoted 4 lines
drivers/scsi/pm8001/pm8001_defs.h +1 -1
@@ -75,7 +75,7 @@ enum port_type {  };
 
 /* driver compile-time configuration */
-#define        PM8001_MAX_CCB           512    /* max ccbs supported */
+#define        PM8001_MAX_CCB           256    /* max ccbs supported */

Hi Deepack,

Quoted 6 lines
Quoted 2 lines

Why do you reduce PM8001_MAX_CCB?
--- PM8001 driver has a memory limit in the machine.

which limit, do you see allocation failure from kernel?
-- I think it depends on machine's capability. For our machines, PM8001_MAX_CCB = 512 caused kernel installation failure. I saw it when I was debugging ncq feature Thanks

Ok, would be helpful to put this info to commit message.

Quoted 1 line

Thanks. I will add this in version 3 of the patchest.

Thanks

#8 lore raw

PATCH v2 2/13 pm80xx : Deal with kexec reboots.

In reply to Deepak Ukey

From: Vikram Auradkar <[email protected]>

A kexec reboot causes the controller fw to assert. This assertion shows up in two ways, the controller doesn't show up as ready and an interrupt is waiting as soon as the handler is registered. To resolve this added below fix:
-split the interrupt handling setup into two parts, setup and
request.
-If the controller ready register indicates not-ready, but that the
not readiness is only on the IOC units we can still try a reset to bring the system back to the pre-reboot state.

---
 drivers/scsi/pm8001/pm8001_init.c | 48 +++++++++++++++++++++++++++++++++++----
 drivers/scsi/pm8001/pm80xx_hwi.c  | 15 ++++++++----
 2 files changed, 54 insertions(+), 9 deletions(-)
drivers/scsi/pm8001/pm8001_init.c +43 -5
index 3f1e755c52c6..a002eb5a3fe4 100644
@@ -248,6 +248,9 @@ static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id)
 	return ret;
 }
 
+static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha);
+static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha);
+
 /**
  * pm8001_alloc - initiate our hba structure and 6 DMAs area.
  * @pm8001_ha:our hba structure.
@@ -890,9 +893,7 @@ static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha)
  */
 static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
 {
-	u32 i = 0, j = 0;
 	u32 number_of_intr;
-	int flag = 0;
 	int rc;
 
 	/* SPCv controllers supports 64 msi-x */
@@ -900,11 +901,11 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
 		number_of_intr = 1;
 	} else {
 		number_of_intr = PM8001_MAX_MSIX_VEC;
-		flag &= ~IRQF_SHARED;
 	}
 
 	rc = pci_alloc_irq_vectors(pm8001_ha->pdev, number_of_intr,
 			number_of_intr, PCI_IRQ_MSIX);
+	number_of_intr = rc;
 	if (rc < 0)
 		return rc;
 	pm8001_ha->number_of_intr = number_of_intr;
@@ -912,8 +913,22 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
 	PM8001_INIT_DBG(pm8001_ha, pm8001_printk(
 		"pci_alloc_irq_vectors request ret:%d no of intr %d\n",
 				rc, pm8001_ha->number_of_intr));
+	return 0;
+}
+
+static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha)
+{
+	u32 i = 0, j = 0;
+	int flag = 0, rc = 0;
 
-	for (i = 0; i < number_of_intr; i++) {
+	if (pm8001_ha->chip_id != chip_8001)
+		flag &= ~IRQF_SHARED;
+
+	PM8001_INIT_DBG(pm8001_ha,
+		pm8001_printk("pci_enable_msix request number of intr %d\n",
+		pm8001_ha->number_of_intr));
+
+	for (i = 0; i < pm8001_ha->number_of_intr; i++) {
 		snprintf(pm8001_ha->intr_drvname[i],
 			sizeof(pm8001_ha->intr_drvname[0]),
 			"%s-%d", pm8001_ha->name, i);
@@ -938,6 +953,21 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha)
 }
 #endif
 
+static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha)
+{
+	struct pci_dev *pdev;
+
+	pdev = pm8001_ha->pdev;
+
+#ifdef PM8001_USE_MSIX
+	if (pci_find_capability(pdev, PCI_CAP_ID_MSIX))
+		return pm8001_setup_msix(pm8001_ha);
+	PM8001_INIT_DBG(pm8001_ha,
+		pm8001_printk("MSIX not supported!!!\n"));
+#endif
+	return 0;
+}
+
 /**
  * pm8001_request_irq - register interrupt
  * @chip_info: our ha struct.
@@ -951,7 +981,7 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha)
 
 #ifdef PM8001_USE_MSIX
 	if (pdev->msix_cap && pci_msi_enabled())
-		return pm8001_setup_msix(pm8001_ha);
+		return pm8001_request_msix(pm8001_ha);
 	else {
 		PM8001_INIT_DBG(pm8001_ha,
 			pm8001_printk("MSIX not supported!!!\n"));
@@ -1033,6 +1063,13 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
 		rc = -ENOMEM;
 		goto err_out_free;
 	}
+	/* Setup Interrupt */
+	rc = pm8001_setup_irq(pm8001_ha);
+	if (rc)	{
+		PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+			"pm8001_setup_irq failed [ret: %d]\n", rc));
+		goto err_out_shost;
+	}
 	list_add_tail(&pm8001_ha->list, &hba_list);
 	PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
 	rc = PM8001_CHIP_DISP->chip_init(pm8001_ha);
@@ -1045,6 +1082,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
 	rc = scsi_add_host(shost, &pdev->dev);
 	if (rc)
 		goto err_out_ha_free;
+	/* Request Interrupt */
 	rc = pm8001_request_irq(pm8001_ha);
 	if (rc)	{
 		PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
drivers/scsi/pm8001/pm80xx_hwi.c +11 -4
index 98dcdbd146d5..d805fd036ddf 100644
@@ -1438,11 +1438,18 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha)
 	if (!pm8001_ha->controller_fatal_error) {
 		/* Check if MPI is in ready state to reset */
 		if (mpi_uninit_check(pm8001_ha) != 0) {
-			regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+			u32 r0 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0);
+			u32 r1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1);
+			u32 r2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2);
+			u32 r3 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3);
 			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
-				"MPI state is not ready scratch1 :0x%x\n",
-				regval));
-			return -1;
+				"MPI state is not ready scratch: %x:%x:%x:%x\n",
+				r0, r1, r2, r3));
+			/* if things aren't ready but the bootloader is ok then
+			 * try the reset anyway.
+			 */
+			if (r1 & SCRATCH_PAD1_BOOTSTATE_MASK)
+				return -1;
 		}
 	}
 	/* checked for reset register normal state; 0x0 */
Signature · 1 line
2.16.3
#9 lore raw

PATCH v2 3/13 pm80xx : Free the tag when mpi_set_phy_profile_resp is received.

In reply to Deepak Ukey

From: yuuzheng <[email protected]>

In pm80xx driver, the command mpi_set_phy_profile_req is sent by host during boot to configure the phy profile such as analog setting page, rate control page. However, the tag is not freed when its response is received. As a result, 16 tags are missing for each HBA after boot. When NCQ is enabled with queue depth 16, it needs at least, 15 * 16 = 240 tags for each HBA to achieve the best performance. In current pm80xx driver with setting CCB_MAX = 256, the total number of tags in each HBA is 255 for data IO. Hence, without returning those tags to the pool after boot, some device will finally be forced to non-ncq mode by ATA layer due to excessive errors (i.e. LLDD cannot allocate tag for queued task).

---
 drivers/scsi/pm8001/pm80xx_hwi.c | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/scsi/pm8001/pm80xx_hwi.c +7 -3
index d805fd036ddf..37b82d7aa3d7 100644
@@ -3715,28 +3715,32 @@ static int mpi_flash_op_ext_resp(struct pm8001_hba_info *pm8001_ha, void *piomb)
 static int mpi_set_phy_profile_resp(struct pm8001_hba_info *pm8001_ha,
 			void *piomb)
 {
+	u32 tag;
 	u8 page_code;
+	int rc = 0;
 	struct set_phy_profile_resp *pPayload =
 		(struct set_phy_profile_resp *)(piomb + 4);
 	u32 ppc_phyid = le32_to_cpu(pPayload->ppc_phyid);
 	u32 status = le32_to_cpu(pPayload->status);
 
+	tag = le32_to_cpu(pPayload->tag);
 	page_code = (u8)((ppc_phyid & 0xFF00) >> 8);
 	if (status) {
 		/* status is FAILED */
 		PM8001_FAIL_DBG(pm8001_ha,
 			pm8001_printk("PhyProfile command failed  with status "
 			"0x%08X \n", status));
-		return -1;
+		rc = -1;
 	} else {
 		if (page_code != SAS_PHY_ANALOG_SETTINGS_PAGE) {
 			PM8001_FAIL_DBG(pm8001_ha,
 				pm8001_printk("Invalid page code 0x%X\n",
 					page_code));
-			return -1;
+			rc = -1;
 		}
 	}
-	return 0;
+	pm8001_tag_free(pm8001_ha, tag);
+	return rc;
 }
 
 /**
Signature · 1 line
2.16.3
#10 lore raw

PATCH v2 4/13 pm80xx : Cleanup initialization loading fail path.

In reply to Deepak Ukey

From: Peter Chang <[email protected]>

1)Move the instance tracking down after we think the instance is good to go. avoids having a use-after free.
2)There are goto targets for trying to cleanup if the hw fails to initialize, but there's some overlap depending on who thinks they own the sub-structures.

---
 drivers/scsi/pm8001/pm8001_init.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/scsi/pm8001/pm8001_init.c +11 -6
index a002eb5a3fe4..775517f9b39d 100644
@@ -1016,6 +1016,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
 	struct pm8001_hba_info *pm8001_ha;
 	struct Scsi_Host *shost = NULL;
 	const struct pm8001_chip_info *chip;
+	struct sas_ha_struct *sha;
 
 	dev_printk(KERN_INFO, &pdev->dev,
 		"pm80xx: driver version %s\n", DRV_VERSION);
@@ -1044,12 +1045,12 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
 		goto err_out_regions;
 	}
 	chip = &pm8001_chips[ent->driver_data];
-	SHOST_TO_SAS_HA(shost) =
-		kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL);
-	if (!SHOST_TO_SAS_HA(shost)) {
+	sha = kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL);
+	if (!sha) {
 		rc = -ENOMEM;
 		goto err_out_free_host;
 	}
+	SHOST_TO_SAS_HA(shost) = sha;
 
 	rc = pm8001_prep_sas_ha_init(shost, chip);
 	if (rc) {
@@ -1070,7 +1071,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
 			"pm8001_setup_irq failed [ret: %d]\n", rc));
 		goto err_out_shost;
 	}
-	list_add_tail(&pm8001_ha->list, &hba_list);
+
 	PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha);
 	rc = PM8001_CHIP_DISP->chip_init(pm8001_ha);
 	if (rc) {
@@ -1105,8 +1106,12 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
 
 	pm8001_post_sas_ha_init(shost, chip);
 	rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
-	if (rc)
+	if (rc) {
+		PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+			"sas_register_ha failed [ret: %d]\n", rc));
 		goto err_out_shost;
+	}
+	list_add_tail(&pm8001_ha->list, &hba_list);
 	scsi_scan_host(pm8001_ha->shost);
 	pm8001_ha->flags = PM8001F_RUN_TIME;
 	return 0;
@@ -1116,7 +1121,7 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
 err_out_ha_free:
 	pm8001_free(pm8001_ha);
 err_out_free:
-	kfree(SHOST_TO_SAS_HA(shost));
+	kfree(sha);
 err_out_free_host:
 	scsi_host_put(shost);
 err_out_regions:
Signature · 1 line
2.16.3
#11 lore raw

PATCH v2 5/13 pm80xx : Support for char device.

In reply to Deepak Ukey

From: Deepak Ukey <[email protected]>

Added the support to register the char device for pm80xx module so that management utility fetch the different information from driver with the help of IOCTL. Also added the IOCTL functionality to get driver info so that management utility can fetch the information about driver like driver name, driver major number, driver minor number and build number.

---
 drivers/scsi/pm8001/pm8001_ctl.c  | 148 ++++++++++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm8001_ctl.h  |  33 +++++++++
 drivers/scsi/pm8001/pm8001_init.c |   5 ++
 drivers/scsi/pm8001/pm8001_sas.h  |   6 ++
 4 files changed, 192 insertions(+)
drivers/scsi/pm8001/pm8001_ctl.c +148 -0
index 7c6be2ec110d..69458b318a20 100644
@@ -41,6 +41,7 @@
 #include <linux/slab.h>
 #include "pm8001_sas.h"
 #include "pm8001_ctl.h"
+int pm80xx_major = -1;
 
 /* scsi host attributes */
 
@@ -845,3 +846,150 @@ struct device_attribute *pm8001_host_attrs[] = {
 	NULL,
 };
 
+/*
+ * pm8001_open - open the configuration file
+ * @inode: inode being opened
+ * @file: file handle attached
+ *
+ * Called when the configuration device is opened. Does the needed
+ * set up on the handle and then returns
+ *
+ */
+static int pm8001_open(struct inode *inode, struct file *file)
+{
+	struct pm8001_hba_info *pm8001_ha;
+	unsigned int minor_number = iminor(inode);
+	int err = -ENODEV;
+
+	list_for_each_entry(pm8001_ha, &hba_list, list) {
+		if (pm8001_ha->id == minor_number) {
+			file->private_data = pm8001_ha;
+			err = 0;
+			break;
+		}
+	}
+
+	return err;
+}
+
+/**
+ * pm8001_close - close the configuration file
+ * @inode: inode being opened
+ * @file: file handle attached
+ *
+ * Called when the configuration device is closed. Does the needed
+ * set up on the handle and then returns
+ *
+ */
+static int pm8001_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+static long pm8001_info_ioctl(struct pm8001_hba_info *pm8001_ha,
+					unsigned long arg)
+{
+	u32 ret = 0;
+	struct ioctl_info_buffer info_buf;
+
+	strcpy(info_buf.information.sz_name, DRV_NAME);
+
+	info_buf.information.usmajor_revision = DRV_MAJOR;
+	info_buf.information.usminor_revision = DRV_MINOR;
+	info_buf.information.usbuild_revision = DRV_BUILD;
+	if (pm8001_ha->chip_id == chip_8001) {
+		info_buf.information.maxoutstandingIO =
+			pm8001_ha->main_cfg_tbl.pm8001_tbl.max_out_io;
+		info_buf.information.maxdevices =
+			(pm8001_ha->main_cfg_tbl.pm8001_tbl.max_sgl >> 16) &
+			0xFFFF;
+	} else {
+		info_buf.information.maxoutstandingIO =
+			pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_out_io;
+		info_buf.information.maxdevices =
+			(pm8001_ha->main_cfg_tbl.pm80xx_tbl.max_sgl >> 16) &
+			0xFFFF;
+	}
+	info_buf.header.return_code = ADPT_IOCTL_CALL_SUCCESS;
+
+	if (copy_to_user((void *)arg, (void *)&info_buf,
+				sizeof(struct ioctl_info_buffer))) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+	}
+	return ret;
+}
+
+/**
+ *	pm8001_ioctl - pm8001 configuration request
+ *	@inode: inode of device
+ *	@file: file handle
+ *	@cmd: ioctl command code
+ *	@arg: argument
+ *
+ *	Handles a configuration ioctl.
+ *
+ */
+static long pm8001_ioctl(struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	u32 ret = -EACCES;
+	struct pm8001_hba_info *pm8001_ha;
+	struct ioctl_header header;
+
+	pm8001_ha = file->private_data;
+
+	switch (cmd) {
+	case ADPT_IOCTL_INFO:
+		ret = pm8001_info_ioctl(pm8001_ha, arg);
+		break;
+	default:
+		ret = ADPT_IOCTL_CALL_INVALID_CODE;
+	}
+
+	if (ret == 0)
+		return ret;
+	header.return_code = ret;
+	ret = -EACCES;
+	if (copy_to_user((void *)arg, (void *)&header,
+				sizeof(struct ioctl_header))) {
+		PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("copy_to_user failed\n"));
+	}
+	return ret;
+}
+
+static const struct file_operations pm8001_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pm8001_open,
+	.release	= pm8001_close,
+	.unlocked_ioctl	= pm8001_ioctl,
+};
+
+/**
+ * pm8001_setup_chrdev - register char device
+ * Return value:
+ * 0 in case of success, otherwise non-zero value
+ */
+int pm8001_setup_chrdev(void)
+{
+	pm80xx_major = register_chrdev(0, DRV_NAME, &pm8001_fops);
+	if (pm80xx_major < 0) {
+		pr_warn("pm8001: unable to register %s  device.\n",
+				DRV_NAME);
+		return pm80xx_major;
+	}
+	return 0;
+}
+
+/**
+ * pm8001_release_chrdev - unregisters per-adapter management interface
+ * Return value:
+ * none
+ */
+void pm8001_release_chrdev(void)
+{
+	if (pm80xx_major > -1) {
+		unregister_chrdev(pm80xx_major, DRV_NAME);
+		pm80xx_major = -1;
+	}
+}
drivers/scsi/pm8001/pm8001_ctl.h +33 -0
index d0d43a250b9e..f0f8b1deae27 100644
@@ -59,5 +59,38 @@
 #define SYSFS_OFFSET                    1024
 #define PM80XX_IB_OB_QUEUE_SIZE         (32 * 1024)
 #define PM8001_IB_OB_QUEUE_SIZE         (16 * 1024)
+
+#define ADPT_IOCTL_CALL_SUCCESS		0x00
+#define ADPT_IOCTL_CALL_FAILED		0x01
+#define ADPT_IOCTL_CALL_INVALID_CODE	0x03
+
+struct ioctl_header {
+	u32 io_controller_num;
+	u32 length;
+	u32 return_code;
+	u32 timeout;
+	u16 direction;
+};
+
+struct ioctl_drv_info {
+	u8	sz_name[64];
+	u16	usmajor_revision;
+	u16	usminor_revision;
+	u16	usbuild_revision;
+	u16	reserved0;
+	u32	maxdevices;
+	u32	maxoutstandingIO;
+	u32	reserved[16];
+};
+
+struct ioctl_info_buffer {
+	struct ioctl_header	header;
+	struct ioctl_drv_info	information;
+};
+
+#define ADPT_IOCTL_INFO _IOR(ADPT_MAGIC_NUMBER, 0, struct ioctl_info_buffer *)
+
+#define ADPT_MAGIC_NUMBER	'm'
+
 #endif /* PM8001_CTL_H_INCLUDED */
 
drivers/scsi/pm8001/pm8001_init.c +5 -0
index 775517f9b39d..25e74f1dbd0c 100644
@@ -1421,6 +1421,9 @@ static int __init pm8001_init(void)
 	pm8001_stt = sas_domain_attach_transport(&pm8001_transport_ops);
 	if (!pm8001_stt)
 		goto err_wq;
+	rc = pm8001_setup_chrdev();
+	if (rc)
+		goto err_ctl;
 	rc = pci_register_driver(&pm8001_pci_driver);
 	if (rc)
 		goto err_tp;
@@ -1428,6 +1431,8 @@ static int __init pm8001_init(void)
 
 err_tp:
 	sas_release_transport(pm8001_stt);
+err_ctl:
+	pm8001_release_chrdev();
 err_wq:
 	destroy_workqueue(pm8001_wq);
 err:
drivers/scsi/pm8001/pm8001_sas.h +6 -0
index 93438c8f67da..479aac34d7cc 100644
@@ -59,6 +59,9 @@
 
 #define DRV_NAME		"pm80xx"
 #define DRV_VERSION		"0.1.39"
+#define DRV_MAJOR		1
+#define DRV_MINOR		3
+#define DRV_BUILD		0
 #define PM8001_FAIL_LOGGING	0x01 /* Error message logging */
 #define PM8001_INIT_LOGGING	0x02 /* driver init logging */
 #define PM8001_DISC_LOGGING	0x04 /* discovery layer logging */
@@ -745,6 +748,9 @@ ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf);
 /* ctl shared API */
 extern struct device_attribute *pm8001_host_attrs[];
 
+int pm8001_setup_chrdev(void);
+void pm8001_release_chrdev(void);
+
 static inline void
 pm8001_ccb_task_free_done(struct pm8001_hba_info *pm8001_ha,
 			struct sas_task *task, struct pm8001_ccb_info *ccb,
Signature · 1 line
2.16.3
maintainer
#12 lore raw

Re: [PATCH V2 05/13] pm80xx : Support for char device.

Quoted 9 lines · Deepak Ukey

From: Deepak Ukey <[email protected]>

Added the support to register the char device for pm80xx module so that management utility fetch the different information from driver with the help of IOCTL. Also added the IOCTL functionality to get driver info so that management utility can fetch the information about driver like driver name, driver major number, driver minor number and build number.

Quoted 3 lines

Thanks for the commit message, looks much better. In the past, people are against IOCTL, suggesting netlink,
have you considered that?

Martin, James, what do you think?

Regards,
Jack

#13 lore raw

Re: [PATCH V2 05/13] pm80xx : Support for char device.

Jinpu,

Quoted 2 lines

Thanks for the commit message, looks much better. In the past, people are against IOCTL, suggesting netlink, have you considered that?

Not so keen on adding more ioctls. It's 2020 and all...

Given the nature of the exported information, what's wrong with putting it in sysfs?

Signature · 1 line
Martin K. Petersen	Oracle Linux Engineering
#14 lore raw

RE: [PATCH V2 05/13] pm80xx : Support for char device.

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Martin,

Quoted 2 lines

Thanks for the commit message, looks much better. In the past, people are against IOCTL, suggesting netlink, have you considered that?

Not so keen on adding more ioctls. It's 2020 and all...

Given the nature of the exported information, what's wrong with putting it in sysfs?
-- We have some upcoming patches which uses this IOCTL interface and that cannot be supported through sysfs. Below are the patches in this patchset which requires IOCTL interface. 0007-pm80xx-IOCTL-functionality-to-get-phy-status 0008-pm80xx-IOCTL-functionality-to-get-phy-error
0009-pm80xx-IOCTL-functionality-for-GPIO
0010-pm80xx-IOCTL-functionality-for-SGPIO
0013-pm80xx-IOCTL-functionality-for-TWI-device

Regards,
Deepak

#15 lore raw

Re: [PATCH V2 05/13] pm80xx : Support for char device.

Quoted 8 lines · On 21/01/2020 05:33, [email protected] wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Martin,

Quoted 2 lines

Thanks for the commit message, looks much better. In the past, people are against IOCTL, suggesting netlink, have you considered that?

Quoted 7 lines

Not so keen on adding more ioctls. It's 2020 and all...

Given the nature of the exported information, what's wrong with putting it in sysfs?
-- We have some upcoming patches which uses this IOCTL interface and that cannot be supported through sysfs. Below are the patches in this patchset which requires IOCTL interface. 0007-pm80xx-IOCTL-functionality-to-get-phy-status 0008-pm80xx-IOCTL-functionality-to-get-phy-error

Please note that there definitely seems to be replication of what sysfs already provides in some of these patches:

- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier

- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count

See ***:

root@ubuntu:/sys/class/sas_phy/phy-0:0# ls -l
total 0
lrwxrwxrwx 1 root root    0 Jan 21 12:05 device -> ../../../phy-0:0
-r--r--r-- 1 root root 4096 Jan 21 12:05 device_type
-rw-r--r-- 1 root root 4096 Jan 21 12:05 enable ***
--w------- 1 root root 4096 Jan 21 12:05 hard_reset
-r--r--r-- 1 root root 4096 Jan 21 12:05 initiator_port_protocols
-r--r--r-- 1 root root 4096 Jan 21 12:05 invalid_dword_count ***
--w------- 1 root root 4096 Jan 21 12:05 link_reset
-r--r--r-- 1 root root 4096 Jan 21 12:05 loss_of_dword_sync_count ***
-rw-r--r-- 1 root root 4096 Jan 21 12:05 maximum_linkrate ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 maximum_linkrate_hw ***
-rw-r--r-- 1 root root 4096 Jan 21 12:05 minimum_linkrate ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 minimum_linkrate_hw ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 negotiated_linkrate ***
-r--r--r-- 1 root root 4096 Jan 21 11:58 phy_identifier ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 phy_reset_problem_count ***
drwxr-xr-x 2 root root    0 Jan 21 12:05 power
-r--r--r-- 1 root root 4096 Jan 21 12:05 running_disparity_error_count ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 sas_address
lrwxrwxrwx 1 root root    0 Jan 21 11:45 subsystem -> ../../../../../../../class/sas_phy
-r--r--r-- 1 root root 4096 Jan 21 12:05 target_port_protocols
-rw-r--r-- 1 root root 4096 Jan 21 11:45 uevent

Maybe the other stuff provided in the patches are useful, I don't know. But debugfs seems better for that.

Quoted 2 lines

0009-pm80xx-IOCTL-functionality-for-GPIO
0010-pm80xx-IOCTL-functionality-for-SGPIO

I don't know why an ioctl is required here.

Quoted 1 line

0013-pm80xx-IOCTL-functionality-for-TWI-device

Thanks,
John

#16 lore raw

RE: [PATCH V2 05/13] pm80xx : Support for char device.

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 9 lines · On 21/01/2020 05:33, [email protected] wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Martin,

Quoted 2 lines

Thanks for the commit message, looks much better. In the past, people are against IOCTL, suggesting netlink, have you considered that?

Quoted 7 lines

Not so keen on adding more ioctls. It's 2020 and all...

Given the nature of the exported information, what's wrong with putting it in sysfs?
-- We have some upcoming patches which uses this IOCTL interface and that cannot be supported through sysfs. Below are the patches in this patchset which requires IOCTL interface. 0007-pm80xx-IOCTL-functionality-to-get-phy-status 0008-pm80xx-IOCTL-functionality-to-get-phy-error

Please note that there definitely seems to be replication of what sysfs already provides in some of these patches:

- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier

- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count

See ***:

root@ubuntu:/sys/class/sas_phy/phy-0:0# ls -l total 0
lrwxrwxrwx 1 root root    0 Jan 21 12:05 device -> ../../../phy-0:0
-r--r--r-- 1 root root 4096 Jan 21 12:05 device_type
-rw-r--r-- 1 root root 4096 Jan 21 12:05 enable ***
--w------- 1 root root 4096 Jan 21 12:05 hard_reset
-r--r--r-- 1 root root 4096 Jan 21 12:05 initiator_port_protocols
-r--r--r-- 1 root root 4096 Jan 21 12:05 invalid_dword_count ***
--w------- 1 root root 4096 Jan 21 12:05 link_reset
-r--r--r-- 1 root root 4096 Jan 21 12:05 loss_of_dword_sync_count ***
-rw-r--r-- 1 root root 4096 Jan 21 12:05 maximum_linkrate ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 maximum_linkrate_hw ***
-rw-r--r-- 1 root root 4096 Jan 21 12:05 minimum_linkrate ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 minimum_linkrate_hw ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 negotiated_linkrate ***
-r--r--r-- 1 root root 4096 Jan 21 11:58 phy_identifier ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 phy_reset_problem_count ***
drwxr-xr-x 2 root root    0 Jan 21 12:05 power
-r--r--r-- 1 root root 4096 Jan 21 12:05 running_disparity_error_count ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 sas_address
lrwxrwxrwx 1 root root    0 Jan 21 11:45 subsystem ->
../../../../../../../class/sas_phy
-r--r--r-- 1 root root 4096 Jan 21 12:05 target_port_protocols
-rw-r--r-- 1 root root 4096 Jan 21 11:45 uevent

Maybe the other stuff provided in the patches are useful, I don't know. But debugfs seems better for that.

- 0006-pm80xx-sysfs-attribute-for-number-of-phys
- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier
- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count
- Thanks for addressing it. We can get this info from /sys/class/sas_phy and /sys/class/sas_port so we will drop these above mentioned three patches from the next - patch series.

Quoted 2 lines

0009-pm80xx-IOCTL-functionality-for-GPIO
0010-pm80xx-IOCTL-functionality-for-SGPIO

I don't know why an ioctl is required here.

Quoted 1 line

0013-pm80xx-IOCTL-functionality-for-TWI-device

- 0009-pm80xx-IOCTL-functionality-for-GPIO
- 0010-pm80xx-IOCTL-functionality-for-SGPIO
- 0013-pm80xx-IOCTL-functionality-for-TWI-device
- For the above patches management utility passes command specific information to driver through IOCTL structure, which used by driver to frame the command and - send to FW. We are using the IOCTL interface for the same. Please let us know your thought.

Regards,
Deepak

#17 lore raw

Re: [PATCH V2 05/13] pm80xx : Support for char device.

Quoted 18 lines · On 22/01/2020 08:50, [email protected] wrote:
(quoted diff) +0 -2
-r--r--r-- 1 root root 4096 Jan 21 12:05 running_disparity_error_count ***
-r--r--r-- 1 root root 4096 Jan 21 12:05 sas_address

lrwxrwxrwx 1 root root 0 Jan 21 11:45 subsystem ->
../../../../../../../class/sas_phy

(quoted diff) +0 -2
-r--r--r-- 1 root root 4096 Jan 21 12:05 target_port_protocols
-rw-r--r-- 1 root root 4096 Jan 21 11:45 uevent

Maybe the other stuff provided in the patches are useful, I don't know. But debugfs seems better for that.

- 0006-pm80xx-sysfs-attribute-for-number-of-phys
- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier
- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count
- Thanks for addressing it. We can get this info from /sys/class/sas_phy and /sys/class/sas_port so we will drop these above mentioned three patches from the next - patch series.

Quoted 2 lines

0009-pm80xx-IOCTL-functionality-for-GPIO
0010-pm80xx-IOCTL-functionality-for-SGPIO

Quoted 8 lines

I don't know why an ioctl is required here.

Quoted 1 line

0013-pm80xx-IOCTL-functionality-for-TWI-device

- 0009-pm80xx-IOCTL-functionality-for-GPIO
- 0010-pm80xx-IOCTL-functionality-for-SGPIO
- 0013-pm80xx-IOCTL-functionality-for-TWI-device
- For the above patches management utility passes command specific information to driver through IOCTL structure, which used by driver to frame the command and - send to FW. We are using the IOCTL interface for the same. Please let us know your thought.

So I specifically questioned the SGPIO patch and why it would have an IOCTL, as this function is supported in kernel libsas/SAS transport code as an SMP function.

For the GPIO IOCTL, could you use register a gpio driver to provide a gpiolib sysfs?

As for TWI, it seems to be for serial EEPROM, so you could ask these experts about how to handle it properly in the kernel for standard sysfs interfaces:

:~/linux$ ./scripts/get_maintainer.pl -f drivers/misc/eeprom/eeprom.c
Jean Delvare <[email protected]> (maintainer:LEGACY EEPROM DRIVER)
Arnd Bergmann <[email protected]> (supporter:CHAR and MISC DRIVERS)
Greg Kroah-Hartman <[email protected]> (supporter:CHAR and MISC DRIVERS)

Thanks,
John

#18 lore raw

RE: [PATCH V2 05/13] pm80xx : Support for char device.

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 19 lines · On 22/01/2020 08:50, [email protected] wrote:

-r--r--r-- 1 root root 4096 Jan 21 12:05 running_disparity_error_count
***
-r--r--r-- 1 root root 4096 Jan 21 12:05 sas_address
lrwxrwxrwx 1 root root 0 Jan 21 11:45 subsystem ->
../../../../../../../class/sas_phy

(quoted diff) +0 -2
-r--r--r-- 1 root root 4096 Jan 21 12:05 target_port_protocols
-rw-r--r-- 1 root root 4096 Jan 21 11:45 uevent

Maybe the other stuff provided in the patches are useful, I don't know. But debugfs seems better for that.

- 0006-pm80xx-sysfs-attribute-for-number-of-phys
- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier
- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count
- Thanks for addressing it. We can get this info from /sys/class/sas_phy and /sys/class/sas_port so we will drop these above mentioned three patches from the next - patch series.

Quoted 2 lines

0009-pm80xx-IOCTL-functionality-for-GPIO
0010-pm80xx-IOCTL-functionality-for-SGPIO

Quoted 8 lines

I don't know why an ioctl is required here.

Quoted 1 line

0013-pm80xx-IOCTL-functionality-for-TWI-device

- 0009-pm80xx-IOCTL-functionality-for-GPIO
- 0010-pm80xx-IOCTL-functionality-for-SGPIO
- 0013-pm80xx-IOCTL-functionality-for-TWI-device
- For the above patches management utility passes command specific information to driver through IOCTL structure, which used by driver to frame the command and - send to FW. We are using the IOCTL interface for the same. Please let us know your thought.

So I specifically questioned the SGPIO patch and why it would have an IOCTL, as this function is supported in kernel libsas/SAS transport code as an SMP function.

Quoted 1 line

Thank you for your suggestions. We will make use of function supported in libsas.

For the GPIO IOCTL, could you use register a gpio driver to provide a gpiolib sysfs?

Quoted 3 lines

We cannot use GPIO driver to provide gpiolib sysfs. There are 24 GPIO signals pin provided by the SPCV controller out of which 16 signals pin are used by customer. The host application perform different operations on that pins for example pin setup, event setup and read/write GPIO pins. For this, applications passes different combination of values to execute the specific operation with help of a payload structure and application passes that structure to driver using IOCTL.
Driver fetch the information like input enable pin setup, typepart1/typepart2 pin setup, gpio event level setup, gpio rising / falling edge setup, gpio pin mask setup passed by application and then send with specific command format to execute the gpio operation.

As for TWI, it seems to be for serial EEPROM, so you could ask these experts about how to handle it properly in the kernel for standard sysfs interfaces:

Quoted 2 lines

Driver supports different TWI devices not limited to the Serial EEPROM. Application passes the address of the attached TWI device to read and write the TWI binary along with the payload structure which contains information like offset, address mode, read/write size. Drivers fetch the information passed by application and then send with specific command format to execute operation.

:~/linux$ ./scripts/get_maintainer.pl -f drivers/misc/eeprom/eeprom.c Jean Delvare <[email protected]> (maintainer:LEGACY EEPROM DRIVER) Arnd Bergmann <[email protected]> (supporter:CHAR and MISC DRIVERS) Greg Kroah-Hartman <[email protected]> (supporter:CHAR and MISC
DRIVERS)

Thanks,
Deepak

maintainer
#19 lore raw

Re: [PATCH V2 05/13] pm80xx : Support for char device.

Quoted 23 lines · On Tue, Jan 28, 2020 at 10:43 AM <[email protected]> wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 18 lines · On 22/01/2020 08:50, [email protected] wrote:

-r--r--r-- 1 root root 4096 Jan 21 12:05 running_disparity_error_count
***
-r--r--r-- 1 root root 4096 Jan 21 12:05 sas_address
lrwxrwxrwx 1 root root 0 Jan 21 11:45 subsystem ->
../../../../../../../class/sas_phy

(quoted diff) +0 -2
-r--r--r-- 1 root root 4096 Jan 21 12:05 target_port_protocols
-rw-r--r-- 1 root root 4096 Jan 21 11:45 uevent

Maybe the other stuff provided in the patches are useful, I don't know. But debugfs seems better for that.

- 0006-pm80xx-sysfs-attribute-for-number-of-phys
- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier
- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count
- Thanks for addressing it. We can get this info from /sys/class/sas_phy and /sys/class/sas_port so we will drop these above mentioned three patches from the next - patch series.

Quoted 6 lines
Quoted 3 lines

- 0009-pm80xx-IOCTL-functionality-for-GPIO
- 0013-pm80xx-IOCTL-functionality-for-TWI-device
- For the above patches management utility passes command specific information to driver through IOCTL structure, which used by driver to frame the command and - send to FW. We are using the IOCTL interface for the same. Please let us know your thought.

So I specifically questioned the SGPIO patch and why it would have an IOCTL, as this function is supported in kernel libsas/SAS transport code as an SMP function.

Quoted 1 line

Thank you for your suggestions. We will make use of function supported in libsas.

So basically you only need IOCTL for GPIO and TWI devices, others can implement via libsas interface or from sysfs directly.

I would like to suggest you do send out other changes without the IOCTL parts first, and consider again Is it really needed by the user to control GPIO and TWI, and if there is other way to do it?

Sorry, I don't have a better suggestion!

Regards,
Jack Wang

#20 lore raw

Re: [PATCH V2 05/13] pm80xx : Support for char device.

Quoted 31 lines · Jinpu Wang
Quoted 23 lines · On Tue, Jan 28, 2020 at 10:43 AM <[email protected]> wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 18 lines · On 22/01/2020 08:50, [email protected] wrote:

-r--r--r-- 1 root root 4096 Jan 21 12:05 running_disparity_error_count
***
-r--r--r-- 1 root root 4096 Jan 21 12:05 sas_address
lrwxrwxrwx 1 root root 0 Jan 21 11:45 subsystem ->
../../../../../../../class/sas_phy

(quoted diff) +0 -2
-r--r--r-- 1 root root 4096 Jan 21 12:05 target_port_protocols
-rw-r--r-- 1 root root 4096 Jan 21 11:45 uevent

Maybe the other stuff provided in the patches are useful, I don't know. But debugfs seems better for that.

- 0006-pm80xx-sysfs-attribute-for-number-of-phys
- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier
- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count
- Thanks for addressing it. We can get this info from /sys/class/sas_phy and /sys/class/sas_port so we will drop these above mentioned three patches from the next - patch series.

Quoted 6 lines
Quoted 3 lines

- 0009-pm80xx-IOCTL-functionality-for-GPIO
- 0013-pm80xx-IOCTL-functionality-for-TWI-device
- For the above patches management utility passes command specific information to driver through IOCTL structure, which used by driver to frame the command and - send to FW. We are using the IOCTL interface for the same. Please let us know your thought.

So I specifically questioned the SGPIO patch and why it would have an IOCTL, as this function is supported in kernel libsas/SAS transport code as an SMP function.

Quoted 1 line

Thank you for your suggestions. We will make use of function supported in libsas.

Quoted 8 lines

So basically you only need IOCTL for GPIO and TWI devices, others can implement via libsas interface or from sysfs directly.

I would like to suggest you do send out other changes without the IOCTL parts first, and consider again Is it really needed by the user to control GPIO and TWI, and if there is other way to do it?

Sorry, I don't have a better suggestion!

LSI SAS HBAs (LSI now owned by Broadcom) implement an internal ** SMP target. It can be seen here:

# ls /dev/bsg
3:0:0:0  3:0:3:0  8:0:0:0  8:0:0:3	     end_device-3:1    expander-3:0
3:0:1:0  4:0:0:0  8:0:0:1  8:0:0:4	     end_device-3:1:0  expander-3:1
3:0:2:0  7:0:0:0  8:0:0:2  end_device-3:0:1  end_device-3:2    sas_host3

It is the last device node: "sas_host3". How do I know it is a SMP target? Because this works:

# smp_read_gpio /dev/bsg/sas_host3
Read GPIO register response:
  GPIO_CFG[0]:
    version: 0
    GPIO enable: 1
    cfg register count: 2
    gp register count: 1
    supported drive count: 16

When you work out what LSI are doing with this, perhaps you could write an article about it and make it publicly available.
It is always a good idea to see how your competitors solve problems :-)

Doug Gilbert

** I call it "internal" because it is not seen when doing a SMP DISCOVER
on a SAS expander to which that SAS HBA is connected.

maintainer
#21 lore raw

Re: [PATCH V2 05/13] pm80xx : Support for char device.

Quoted 62 lines · Douglas Gilbert
Quoted 31 lines · Jinpu Wang
Quoted 23 lines · On Tue, Jan 28, 2020 at 10:43 AM <[email protected]> wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 18 lines · On 22/01/2020 08:50, [email protected] wrote:

-r--r--r-- 1 root root 4096 Jan 21 12:05 running_disparity_error_count
***
-r--r--r-- 1 root root 4096 Jan 21 12:05 sas_address
lrwxrwxrwx 1 root root 0 Jan 21 11:45 subsystem ->
../../../../../../../class/sas_phy

(quoted diff) +0 -2
-r--r--r-- 1 root root 4096 Jan 21 12:05 target_port_protocols
-rw-r--r-- 1 root root 4096 Jan 21 11:45 uevent

Maybe the other stuff provided in the patches are useful, I don't know. But debugfs seems better for that.

- 0006-pm80xx-sysfs-attribute-for-number-of-phys
- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier
- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count
- Thanks for addressing it. We can get this info from /sys/class/sas_phy and /sys/class/sas_port so we will drop these above mentioned three patches from the next - patch series.

Quoted 6 lines
Quoted 3 lines

- 0009-pm80xx-IOCTL-functionality-for-GPIO
- 0013-pm80xx-IOCTL-functionality-for-TWI-device
- For the above patches management utility passes command specific information to driver through IOCTL structure, which used by driver to frame the command and - send to FW. We are using the IOCTL interface for the same. Please let us know your thought.

So I specifically questioned the SGPIO patch and why it would have an IOCTL, as this function is supported in kernel libsas/SAS transport code as an SMP function.

Quoted 1 line

Thank you for your suggestions. We will make use of function supported in libsas.

Quoted 8 lines

So basically you only need IOCTL for GPIO and TWI devices, others can implement via libsas interface or from sysfs directly.

I would like to suggest you do send out other changes without the IOCTL parts first, and consider again Is it really needed by the user to control GPIO and TWI, and if there is other way to do it?

Sorry, I don't have a better suggestion!

LSI SAS HBAs (LSI now owned by Broadcom) implement an internal ** SMP target. It can be seen here:

# ls /dev/bsg
3:0:0:0  3:0:3:0  8:0:0:0  8:0:0:3           end_device-3:1    expander-3:0
3:0:1:0  4:0:0:0  8:0:0:1  8:0:0:4           end_device-3:1:0  expander-3:1
3:0:2:0  7:0:0:0  8:0:0:2  end_device-3:0:1  end_device-3:2    sas_host3

It is the last device node: "sas_host3". How do I know it is a SMP target? Because this works:

# smp_read_gpio /dev/bsg/sas_host3
Read GPIO register response:
   GPIO_CFG[0]:
     version: 0
     GPIO enable: 1
     cfg register count: 2
     gp register count: 1
     supported drive count: 16
Quoted 3 lines

When you work out what LSI are doing with this, perhaps you could write an article about it and make it publicly available.
It is always a good idea to see how your competitors solve problems :-)

This sounds indeed a better solution, thanks for the info, Doug

@Deepak Ukey can you check if you guys can also do it this way?

Regards,
Jack Wang

#22 lore raw

Re: [PATCH V2 05/13] pm80xx : Support for char device.

Quoted 54 lines · Jinpu Wang
Quoted 53 lines · Douglas Gilbert
Quoted 31 lines · Jinpu Wang
Quoted 23 lines · On Tue, Jan 28, 2020 at 10:43 AM <[email protected]> wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 18 lines · On 22/01/2020 08:50, [email protected] wrote:

-r--r--r-- 1 root root 4096 Jan 21 12:05 running_disparity_error_count
***
-r--r--r-- 1 root root 4096 Jan 21 12:05 sas_address
lrwxrwxrwx 1 root root 0 Jan 21 11:45 subsystem ->
../../../../../../../class/sas_phy

(quoted diff) +0 -2
-r--r--r-- 1 root root 4096 Jan 21 12:05 target_port_protocols
-rw-r--r-- 1 root root 4096 Jan 21 11:45 uevent

Maybe the other stuff provided in the patches are useful, I don't know. But debugfs seems better for that.

- 0006-pm80xx-sysfs-attribute-for-number-of-phys
- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier
- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count
- Thanks for addressing it. We can get this info from /sys/class/sas_phy and /sys/class/sas_port so we will drop these above mentioned three patches from the next - patch series.

Quoted 6 lines
Quoted 3 lines

- 0009-pm80xx-IOCTL-functionality-for-GPIO
- 0013-pm80xx-IOCTL-functionality-for-TWI-device
- For the above patches management utility passes command specific information to driver through IOCTL structure, which used by driver to frame the command and - send to FW. We are using the IOCTL interface for the same. Please let us know your thought.

So I specifically questioned the SGPIO patch and why it would have an IOCTL, as this function is supported in kernel libsas/SAS transport code as an SMP function.

Quoted 1 line

Thank you for your suggestions. We will make use of function supported in libsas.

Quoted 8 lines

So basically you only need IOCTL for GPIO and TWI devices, others can implement via libsas interface or from sysfs directly.

I would like to suggest you do send out other changes without the IOCTL parts first, and consider again Is it really needed by the user to control GPIO and TWI, and if there is other way to do it?

Sorry, I don't have a better suggestion!

LSI SAS HBAs (LSI now owned by Broadcom) implement an internal ** SMP target. It can be seen here:

# ls /dev/bsg
3:0:0:0  3:0:3:0  8:0:0:0  8:0:0:3           end_device-3:1    expander-3:0
3:0:1:0  4:0:0:0  8:0:0:1  8:0:0:4           end_device-3:1:0  expander-3:1
3:0:2:0  7:0:0:0  8:0:0:2  end_device-3:0:1  end_device-3:2    sas_host3

It is the last device node: "sas_host3". How do I know it is a SMP target? Because this works:

Quoted 9 lines
Quoted 9 lines
# smp_read_gpio /dev/bsg/sas_host3
Read GPIO register response:
    GPIO_CFG[0]:
      version: 0
      GPIO enable: 1
      cfg register count: 2
      gp register count: 1
      supported drive count: 16

JFYI, that specific command is not implemented for libsas SMP host handler (see https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/scsi/libsas/sas_host_smp.c?h=v5.6-rc5#n278), but the write command should be ok

Quoted 2 lines
Quoted 2 lines

When you work out what LSI are doing with this, perhaps you could write an article about it and make it publicly available.

Firmware magic...

Quoted 9 lines
Quoted 1 line

It is always a good idea to see how your competitors solve problems :-)

This sounds indeed a better solution, thanks for the info, Doug

@Deepak Ukey can you check if you guys can also do it this way?

Regards,
Jack Wang
.

#23 lore raw

RE: [PATCH V2 05/13] pm80xx : Support for char device.

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 56 lines · Jinpu Wang
Quoted 55 lines · Douglas Gilbert
Quoted 33 lines · Jinpu Wang
Quoted 25 lines · On Tue, Jan 28, 2020 at 10:43 AM <[email protected]> wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 19 lines · On 22/01/2020 08:50, [email protected] wrote:

-r--r--r-- 1 root root 4096 Jan 21 12:05 running_disparity_error_count
***
-r--r--r-- 1 root root 4096 Jan 21 12:05 sas_address
lrwxrwxrwx 1 root root 0 Jan 21 11:45 subsystem ->
../../../../../../../class/sas_phy

(quoted diff) +0 -2
-r--r--r-- 1 root root 4096 Jan 21 12:05 target_port_protocols
-rw-r--r-- 1 root root 4096 Jan 21 11:45 uevent

Maybe the other stuff provided in the patches are useful, I don't know. But debugfs seems better for that.

- 0006-pm80xx-sysfs-attribute-for-number-of-phys
- 0007-pm80xx-IOCTL-functionality-to-get-phy-status gets things like Programmed Link Rate, Negotiated Link Rate, PHY Identifier
- 0008-pm80xx-IOCTL-functionality-to-get-phy-error provides other things like Invalid Dword Error Count, Disparity Error Count
- Thanks for addressing it. We can get this info from /sys/class/sas_phy and /sys/class/sas_port so we will drop these above mentioned three patches from the next - patch series.

Quoted 6 lines
Quoted 3 lines

- 0009-pm80xx-IOCTL-functionality-for-GPIO
- 0013-pm80xx-IOCTL-functionality-for-TWI-device
- For the above patches management utility passes command specific information to driver through IOCTL structure, which used by driver to frame the command and - send to FW. We are using the IOCTL interface for the same. Please let us know your thought.

So I specifically questioned the SGPIO patch and why it would have an IOCTL, as this function is supported in kernel libsas/SAS transport code as an SMP function.

Quoted 1 line

Thank you for your suggestions. We will make use of function supported in libsas.

Quoted 8 lines

So basically you only need IOCTL for GPIO and TWI devices, others can implement via libsas interface or from sysfs directly.

I would like to suggest you do send out other changes without the IOCTL parts first, and consider again Is it really needed by the user to control GPIO and TWI, and if there is other way to do it?

Sorry, I don't have a better suggestion!

LSI SAS HBAs (LSI now owned by Broadcom) implement an internal ** SMP target. It can be seen here:

# ls /dev/bsg
3:0:0:0  3:0:3:0  8:0:0:0  8:0:0:3           end_device-3:1    expander-3:0
3:0:1:0  4:0:0:0  8:0:0:1  8:0:0:4           end_device-3:1:0  expander-3:1
3:0:2:0  7:0:0:0  8:0:0:2  end_device-3:0:1  end_device-3:2    sas_host3

It is the last device node: "sas_host3". How do I know it is a SMP target? Because this works:

Quoted 9 lines
Quoted 9 lines
# smp_read_gpio /dev/bsg/sas_host3
Read GPIO register response:
    GPIO_CFG[0]:
      version: 0
      GPIO enable: 1
      cfg register count: 2
      gp register count: 1
      supported drive count: 16

JFYI, that specific command is not implemented for libsas SMP host handler (see https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/scsi/libsas/sas_host_smp.c?h=v5.6-rc5#n278),
but the write command should be ok

Quoted 2 lines
Quoted 2 lines

When you work out what LSI are doing with this, perhaps you could write an article about it and make it publicly available.

Firmware magic...

Quoted 5 lines
Quoted 2 lines

It is always a good idea to see how your competitors solve problems :-)

This sounds indeed a better solution, thanks for the info, Doug

@Deepak Ukey can you check if you guys can also do it this way?

We are going to submit the version 3 of the patchset without IOCTL patches and in future we will come up with the different solution for IOCTL patches. Also we will go through the solution suggested by Doug.

Quoted 5 lines

Regards,
Deepak
.

#24 lore raw

PATCH v2 6/13 pm80xx : sysfs attribute for number of phys.

In reply to Deepak Ukey

From: Viswas G <[email protected]>

Added sysfs attribute to show number of phys.

---
 drivers/scsi/pm8001/pm8001_ctl.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
drivers/scsi/pm8001/pm8001_ctl.c +20 -0
index 69458b318a20..8091e78a04b0 100644
@@ -89,6 +89,25 @@ static ssize_t controller_fatal_error_show(struct device *cdev,
 }
 static DEVICE_ATTR_RO(controller_fatal_error);
 
+/**
+ * num_phys_show - Number of phys
+ * @cdev:pointer to embedded class device
+ * @buf:the buffer returned
+ * A sysfs 'read-only' shost attribute.
+ */
+static ssize_t num_phys_show(struct device *cdev,
+		struct device_attribute *attr, char *buf)
+{
+	int ret;
+	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;
+
+	ret = sprintf(buf, "%d", pm8001_ha->chip->n_phy);
+	return ret;
+}
+static DEVICE_ATTR_RO(num_phys);
+
 /**
  * pm8001_ctl_fw_version_show - firmware version
  * @cdev: pointer to embedded class device
@@ -825,6 +844,7 @@ static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP,
 struct device_attribute *pm8001_host_attrs[] = {
 	&dev_attr_interface_rev,
 	&dev_attr_controller_fatal_error,
+	&dev_attr_num_phys,
 	&dev_attr_fw_version,
 	&dev_attr_update_fw,
 	&dev_attr_aap_log,
Signature · 1 line
2.16.3
maintainer
#25 lore raw

Re: [PATCH V2 06/13] pm80xx : sysfs attribute for number of phys.

Quoted 8 lines · Deepak Ukey

From: Viswas G <[email protected]>

Added sysfs attribute to show number of phys.

I agree with John Gary, the mgmt tool can get the info from /sys/class/sas_phy, no need to add an extra sysfs.

I suggest dropping the patch.

Thanks!

#26 lore raw

RE: [PATCH V2 06/13] pm80xx : sysfs attribute for number of phys.

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 8 lines · Deepak Ukey

From: Viswas G <[email protected]>

Added sysfs attribute to show number of phys.

I agree with John Gary, the mgmt tool can get the info from /sys/class/sas_phy, no need to add an extra sysfs.

I suggest dropping the patch.

Quoted 1 line

We have HBA application already in use by customer which uses this sysfs entry. So is it fine to keep this patch?

Thanks!

maintainer
#27 lore raw

Re: [PATCH V2 06/13] pm80xx : sysfs attribute for number of phys.

Quoted 10 lines · On Mon, Jan 20, 2020 at 5:50 AM <[email protected]> wrote:

EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe

Quoted 5 lines · Deepak Ukey

From: Viswas G <[email protected]>

Added sysfs attribute to show number of phys.

Quoted 8 lines
Quoted 3 lines

I agree with John Gary, the mgmt tool can get the info from /sys/class/sas_phy, no need to add an extra sysfs.

I suggest dropping the patch.

Quoted 1 line

We have HBA application already in use by customer which uses this sysfs entry. So is it fine to keep this patch?

Thanks!

How much effort to convert the HBA application to use general sas_phy information? IMHO converting HBA application to use general interface is the right way to go.

Thanks

#28 lore raw

PATCH v2 7/13 pm80xx : IOCTL functionality to get phy status.

In reply to Deepak Ukey

From: Viswas G <[email protected]>

Added the IOCTL functionality for phy status so that management utility can get the information like phy id, phy status, port id and port status from driver using get phy profile command.

---
 drivers/scsi/pm8001/pm8001_ctl.c | 90 ++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm8001_ctl.h | 23 +++++++++-
 drivers/scsi/pm8001/pm8001_sas.h |  7 ++++
 drivers/scsi/pm8001/pm80xx_hwi.c | 68 ++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm80xx_hwi.h |  1 +
 5 files changed, 188 insertions(+), 1 deletion(-)
drivers/scsi/pm8001/pm8001_ctl.c +90 -0
index 8091e78a04b0..eb64566b2274 100644
@@ -41,6 +41,8 @@
 #include <linux/slab.h>
 #include "pm8001_sas.h"
 #include "pm8001_ctl.h"
+#include "pm80xx_hwi.h"
+
 int pm80xx_major = -1;
 
 /* scsi host attributes */
@@ -939,6 +941,91 @@ static long pm8001_info_ioctl(struct pm8001_hba_info *pm8001_ha,
 	return ret;
 }
 
+static int pm8001_ioctl_get_phy_profile(struct pm8001_hba_info *pm8001_ha,
+		unsigned long arg)
+{
+	struct phy_profile phy_prof[MAX_NUM_PHYS];
+	int nphys;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long timeout = msecs_to_jiffies(2000);
+	u32 ret = 0, i;
+	int page_code = SAS_PHY_GENERAL_STATUS_PAGE;
+
+	if (pm8001_ha->pdev->device == 0x8001 ||
+				pm8001_ha->pdev->device == 0x8081) {
+		return ADPT_IOCTL_CALL_INVALID_DEVICE;
+	}
+
+	if (copy_from_user(&phy_prof[0], (struct phy_profile *)arg,
+				sizeof(struct phy_profile))) {
+		PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("copy_from_user failed\n"));
+		return ADPT_IOCTL_CALL_FAILED;
+	}
+
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+	nphys = phy_prof[0].phy_id;
+	if (nphys == -1) {
+		for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
+			pm8001_ha->ioctl_completion = &completion;
+			ret = PM8001_CHIP_DISP->get_phy_profile_req(pm8001_ha,
+								i, page_code);
+			if (ret != 0) {
+				PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+					"Get phy profile request failed\n"));
+				ret = ADPT_IOCTL_CALL_FAILED;
+				goto exit;
+			}
+			timeout = wait_for_completion_timeout(&completion,
+					timeout);
+			if (timeout == 0) {
+				ret = ADPT_IOCTL_CALL_FAILED;
+				goto exit;
+			}
+			memcpy((void *)&phy_prof[i],
+				(void *)&pm8001_ha->phy_profile_resp,
+				sizeof(struct phy_profile));
+		}
+
+		if (copy_to_user((void *)arg, (void *)&phy_prof,
+				sizeof(struct phy_profile) * (i))) {
+			PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("copy_to_user failed\n"));
+			ret = ADPT_IOCTL_CALL_FAILED;
+		}
+	} else {
+		pm8001_ha->ioctl_completion = &completion;
+		ret = PM8001_CHIP_DISP->get_phy_profile_req(pm8001_ha,
+							nphys, page_code);
+		if (ret != 0) {
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+				"Get phy profile request failed\n"));
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+		timeout = wait_for_completion_timeout(&completion,
+				timeout);
+		if (timeout == 0) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+
+		if (copy_to_user((void *)arg,
+				(void *)&pm8001_ha->phy_profile_resp,
+				sizeof(struct phy_profile))) {
+			PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("copy_to_user failed\n"));
+			ret = ADPT_IOCTL_CALL_FAILED;
+		}
+	}
+exit:
+	spin_lock_irq(&pm8001_ha->ioctl_lock);
+	pm8001_ha->ioctl_completion = NULL;
+	spin_unlock_irq(&pm8001_ha->ioctl_lock);
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+	return ret;
+}
+
 /**
  *	pm8001_ioctl - pm8001 configuration request
  *	@inode: inode of device
@@ -962,6 +1049,9 @@ static long pm8001_ioctl(struct file *file,
 	case ADPT_IOCTL_INFO:
 		ret = pm8001_info_ioctl(pm8001_ha, arg);
 		break;
+	case ADPT_IOCTL_GET_PHY_PROFILE:
+		ret = pm8001_ioctl_get_phy_profile(pm8001_ha, arg);
+		return ret;
 	default:
 		ret = ADPT_IOCTL_CALL_INVALID_CODE;
 	}
drivers/scsi/pm8001/pm8001_ctl.h +22 -1
index f0f8b1deae27..226fab82845f 100644
@@ -63,6 +63,9 @@
 #define ADPT_IOCTL_CALL_SUCCESS		0x00
 #define ADPT_IOCTL_CALL_FAILED		0x01
 #define ADPT_IOCTL_CALL_INVALID_CODE	0x03
+#define ADPT_IOCTL_CALL_INVALID_DEVICE	0x04
+
+#define MAX_NUM_PHYS			16
 
 struct ioctl_header {
 	u32 io_controller_num;
@@ -88,8 +91,26 @@ struct ioctl_info_buffer {
 	struct ioctl_drv_info	information;
 };
 
-#define ADPT_IOCTL_INFO _IOR(ADPT_MAGIC_NUMBER, 0, struct ioctl_info_buffer *)
+struct phy_profile {
+	char		phy_id;
+	unsigned int	phys:4;
+	unsigned int	nlr:4;
+	unsigned int	plr:4;
+	unsigned int	reserved1:12;
+	unsigned char	port_id;
+	unsigned int	prts:4;
+	unsigned int	reserved2:20;
+} __packed;
 
+struct phy_prof_resp {
+	union {
+		struct phy_profile status;
+	} phy;
+};
+
+#define ADPT_IOCTL_INFO _IOR(ADPT_MAGIC_NUMBER, 0, struct ioctl_info_buffer *)
+#define ADPT_IOCTL_GET_PHY_PROFILE _IOWR(ADPT_MAGIC_NUMBER, 8, \
+		struct phy_profile*)
 #define ADPT_MAGIC_NUMBER	'm'
 
 #endif /* PM8001_CTL_H_INCLUDED */
drivers/scsi/pm8001/pm8001_sas.h +7 -0
index 479aac34d7cc..87d676810a18 100644
@@ -56,6 +56,7 @@
 #include <scsi/sas_ata.h>
 #include <linux/atomic.h>
 #include "pm8001_defs.h"
+#include "pm8001_ctl.h"
 
 #define DRV_NAME		"pm80xx"
 #define DRV_VERSION		"0.1.39"
@@ -246,6 +247,8 @@ struct pm8001_dispatch {
 	int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha,
 		u32 state);
 	int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
+	int (*get_phy_profile_req)(struct pm8001_hba_info *pm8001_ha,
+		int phy, int page);
 };
 
 struct pm8001_chip_info {
@@ -560,6 +563,10 @@ struct pm8001_hba_info {
 	bool			controller_fatal_error;
 	const struct firmware 	*fw_image;
 	struct isr_param irq_vector[PM8001_MAX_MSIX_VEC];
+	spinlock_t		ioctl_lock;
+	struct mutex		ioctl_mutex;
+	struct completion	*ioctl_completion;
+	struct	phy_prof_resp	phy_profile_resp;
 	u32			reset_in_progress;
 };
 
drivers/scsi/pm8001/pm80xx_hwi.c +68 -0

87 lines not on this page · raw message

drivers/scsi/pm8001/pm80xx_hwi.h +1 -0
index 701951a0f715..230877caeed4 100644
@@ -176,6 +176,7 @@
 
 /* phy_profile */
 #define SAS_PHY_ANALOG_SETTINGS_PAGE	0x04
+#define SAS_PHY_GENERAL_STATUS_PAGE	0x05
 #define PHY_DWORD_LENGTH		0xC
 
 /* Thermal related */
Signature · 1 line
2.16.3
maintainer
#29 lore raw

Re: [PATCH V2 07/13] pm80xx : IOCTL functionality to get phy status.

drivers/scsi/pm8001/pm8001_sas.h struct pm8001_hba_info { · line 567

Quoted 7 lines

struct pm8001_chip_info {

drivers/scsi/pm8001/pm8001_sas.h +2 -0
@@ -560,6 +563,10 @@ struct pm8001_hba_info {
        bool                    controller_fatal_error;
        const struct firmware   *fw_image;
        struct isr_param irq_vector[PM8001_MAX_MSIX_VEC];
+       spinlock_t              ioctl_lock;
+       struct mutex            ioctl_mutex;

did you ever initial both lock? why do you need both? I failed to find them.

Quoted 4 lines
drivers/scsi/pm8001/pm8001_sas.h +2 -0
+       struct completion       *ioctl_completion;
+       struct  phy_prof_resp   phy_profile_resp;
        u32                     reset_in_progress;
 };
#30 lore raw

PATCH v2 8/13 pm80xx : IOCTL functionality to get phy error.

In reply to Deepak Ukey

From: Viswas G <[email protected]>

Added the IOCTL functionality for phy error so that management utility can get the information like Invalid dword count, Disparity error count, Loss of sync dword count, phy reset count from driver using get phy profile command.

---
 drivers/scsi/pm8001/pm8001_ctl.c | 54 ++++++++++++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm8001_ctl.h | 12 +++++++++
 drivers/scsi/pm8001/pm80xx_hwi.c | 14 +++++++++++
 drivers/scsi/pm8001/pm80xx_hwi.h |  1 +
 4 files changed, 81 insertions(+)
drivers/scsi/pm8001/pm8001_ctl.c +54 -0
index eb64566b2274..7f45e114a31a 100644
@@ -1026,6 +1026,57 @@ static int pm8001_ioctl_get_phy_profile(struct pm8001_hba_info *pm8001_ha,
 	return ret;
 }
 
+static int pm8001_ioctl_get_phy_err(struct pm8001_hba_info *pm8001_ha,
+		unsigned long arg)
+{
+	struct phy_errcnt phy_err[MAX_NUM_PHYS];
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long timeout = msecs_to_jiffies(2000);
+	u32 ret = 0, i;
+	int page_code = SAS_PHY_ERR_COUNTERS_PAGE;
+	/*6H card does not support phyerr*/
+	if (pm8001_ha->pdev->device == 0x8001 ||
+			pm8001_ha->pdev->device == 0x8081) {
+		return ADPT_IOCTL_CALL_INVALID_DEVICE;
+	}
+
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+
+	for (i = 0; i < pm8001_ha->chip->n_phy; i++) {
+		pm8001_ha->ioctl_completion = &completion;
+		ret = PM8001_CHIP_DISP->get_phy_profile_req(pm8001_ha,
+				i, page_code);
+		if (ret != 0) {
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk(
+				"Get phy profile request failed\n"));
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+		timeout = wait_for_completion_timeout(&completion,
+				timeout);
+		if (timeout == 0) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+		memcpy((void *)&phy_err[i],
+			(void *)&pm8001_ha->phy_profile_resp,
+			sizeof(struct phy_errcnt));
+	}
+
+	if (copy_to_user((void *)arg, (void *)&phy_err,
+				sizeof(struct phy_errcnt) * (i))) {
+		PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("copy_to_user failed\n"));
+		ret = ADPT_IOCTL_CALL_FAILED;
+	}
+exit:
+	spin_lock_irq(&pm8001_ha->ioctl_lock);
+	pm8001_ha->ioctl_completion = NULL;
+	spin_unlock_irq(&pm8001_ha->ioctl_lock);
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+	return ret;
+}
+
 /**
  *	pm8001_ioctl - pm8001 configuration request
  *	@inode: inode of device
@@ -1052,6 +1103,9 @@ static long pm8001_ioctl(struct file *file,
 	case ADPT_IOCTL_GET_PHY_PROFILE:
 		ret = pm8001_ioctl_get_phy_profile(pm8001_ha, arg);
 		return ret;
+	case ADPT_IOCTL_GET_PHY_ERR_CNT:
+		ret = pm8001_ioctl_get_phy_err(pm8001_ha, arg);
+		break;
 	default:
 		ret = ADPT_IOCTL_CALL_INVALID_CODE;
 	}
drivers/scsi/pm8001/pm8001_ctl.h +12 -0
index 226fab82845f..686ad69f0e0c 100644
@@ -102,15 +102,27 @@ struct phy_profile {
 	unsigned int	reserved2:20;
 } __packed;
 
+struct phy_errcnt {
+	unsigned int  InvalidDword;
+	unsigned int  runningDisparityError;
+	unsigned int  codeViolation;
+	unsigned int  LossOfSyncDW;
+	unsigned int  phyResetProblem;
+	unsigned int  inboundCRCError;
+};
+
 struct phy_prof_resp {
 	union {
 		struct phy_profile status;
+		struct phy_errcnt errcnt;
 	} phy;
 };
 
 #define ADPT_IOCTL_INFO _IOR(ADPT_MAGIC_NUMBER, 0, struct ioctl_info_buffer *)
 #define ADPT_IOCTL_GET_PHY_PROFILE _IOWR(ADPT_MAGIC_NUMBER, 8, \
 		struct phy_profile*)
+#define ADPT_IOCTL_GET_PHY_ERR_CNT _IOWR(ADPT_MAGIC_NUMBER, 9, \
+		struct phy_err*)
 #define ADPT_MAGIC_NUMBER	'm'
 
 #endif /* PM8001_CTL_H_INCLUDED */
drivers/scsi/pm8001/pm80xx_hwi.c +14 -0
index 0a36c5d5e2c2..e8af262976d6 100644
@@ -3690,6 +3690,7 @@ static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha,
 {
 	u32 tag, page_code;
 	struct phy_profile *phy_profile, *phy_prof;
+	struct phy_errcnt *phy_err, *phy_err_cnt;
 	struct get_phy_profile_resp *pPayload =
 		(struct get_phy_profile_resp *)(piomb + 4);
 	u32 status = le32_to_cpu(pPayload->status);
@@ -3725,6 +3726,19 @@ static int mpi_get_phy_profile_resp(struct pm8001_hba_info *pm8001_ha,
 			phy_profile->nlr = le32_to_cpu(phy_prof->nlr);
 			phy_profile->port_id = le32_to_cpu(phy_prof->port_id);
 			phy_profile->prts = le32_to_cpu(phy_prof->prts);
+		} else if (page_code == SAS_PHY_ERR_COUNTERS_PAGE) {
+			phy_err =
+			(struct phy_errcnt *)&pm8001_ha->phy_profile_resp;
+			phy_err_cnt =
+			(struct phy_errcnt *)pPayload->ppc_specific_rsp;
+			phy_err->InvalidDword =
+			le32_to_cpu(phy_err_cnt->InvalidDword);
+			phy_err->runningDisparityError =
+			le32_to_cpu(phy_err_cnt->runningDisparityError);
+			phy_err->LossOfSyncDW =
+			le32_to_cpu(phy_err_cnt->LossOfSyncDW);
+			phy_err->phyResetProblem =
+			le32_to_cpu(phy_err_cnt->phyResetProblem);
 		}
 		complete(pm8001_ha->ioctl_completion);
 	}
drivers/scsi/pm8001/pm80xx_hwi.h +1 -0
index 230877caeed4..b5119c5479da 100644
@@ -175,6 +175,7 @@
 #define PHY_STOP_ERR_DEVICE_ATTACHED	0x1046
 
 /* phy_profile */
+#define SAS_PHY_ERR_COUNTERS_PAGE	0x01
 #define SAS_PHY_ANALOG_SETTINGS_PAGE	0x04
 #define SAS_PHY_GENERAL_STATUS_PAGE	0x05
 #define PHY_DWORD_LENGTH		0xC
Signature · 1 line
2.16.3
#31 lore raw

PATCH v2 9/13 pm80xx : IOCTL functionality for GPIO.

In reply to Deepak Ukey

From: Deepak Ukey <[email protected]>

Added IOCTL functionality for GPIO.
The SPCv controller provides 24 GPIO signals. The first 12 signals [11:0] and the last 4 signals [23:20] are for customer use. Eight signals [19:12] are reserved for the SPCv controller firmware. Whenever the host performs GPIO setup or a read/write operation using the GPIO command the host needs to make sure that it does not disturb the GPIO configuration for the bits [19:12]. Each signal can be configured either as an input or as an output. When configured as an output, the host can use the GPIO Command to set the desired level. GPIO inputs can also be configured so that the SPCv controller sends the GPIO Event notification when specific GPIO events occur.
Different GPIO features implemented:
1) GPIO Pin Setup
2) GPIO Event Setup
3) GPIO Read
4) GPIO Write

---
 drivers/scsi/pm8001/pm8001_ctl.c  |  95 ++++++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm8001_ctl.h  |  24 +++++++++
 drivers/scsi/pm8001/pm8001_init.c |   6 +++
 drivers/scsi/pm8001/pm8001_sas.h  |  17 ++++++
 drivers/scsi/pm8001/pm80xx_hwi.c  | 106 ++++++++++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm80xx_hwi.h  |  49 ++++++++++++++++++
 6 files changed, 297 insertions(+)
drivers/scsi/pm8001/pm8001_ctl.c +95 -0
index 7f45e114a31a..cadb5be394b6 100644
@@ -39,6 +39,7 @@
  */
 #include <linux/firmware.h>
 #include <linux/slab.h>
+#include <linux/poll.h>
 #include "pm8001_sas.h"
 #include "pm8001_ctl.h"
 #include "pm80xx_hwi.h"
@@ -941,6 +942,73 @@ static long pm8001_info_ioctl(struct pm8001_hba_info *pm8001_ha,
 	return ret;
 }
 
+static long pm8001_gpio_ioctl(struct pm8001_hba_info *pm8001_ha,
+		unsigned long arg)
+{
+	struct gpio_buffer buffer;
+	struct pm8001_gpio *payload;
+	struct gpio_ioctl_resp *gpio_resp;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long timeout;
+	u32 ret = 0, operation;
+
+	if (pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ADAPTEC2)
+		return ADPT_IOCTL_CALL_INVALID_DEVICE;
+
+	if (copy_from_user(&buffer, (struct gpio_buffer *)arg,
+		sizeof(struct gpio_buffer))) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+	}
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+	pm8001_ha->ioctl_completion = &completion;
+	payload = &buffer.gpio_payload;
+	operation = payload->operation;
+	ret = PM8001_CHIP_DISP->gpio_req(pm8001_ha, payload);
+	if (ret != 0) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+		goto exit;
+	}
+
+	timeout = (unsigned long)buffer.header.timeout * 1000;
+	if (timeout < 2000)
+		timeout = 2000;
+
+	timeout = wait_for_completion_timeout(&completion,
+			msecs_to_jiffies(timeout));
+	if (timeout == 0) {
+		ret = ADPT_IOCTL_CALL_TIMEOUT;
+		goto exit;
+	}
+	gpio_resp = &pm8001_ha->gpio_resp;
+	buffer.header.return_code = ADPT_IOCTL_CALL_SUCCESS;
+
+	if (operation == GPIO_READ) {
+		payload->rd_wr_val		= gpio_resp->gpio_rd_val;
+		payload->input_enable		= gpio_resp->gpio_in_enabled;
+		payload->pinsetup1		= gpio_resp->gpio_pinsetup1;
+		payload->pinsetup2		= gpio_resp->gpio_pinsetup2;
+		payload->event_level		= gpio_resp->gpio_evt_change;
+		payload->event_rising_edge	= gpio_resp->gpio_evt_rise;
+		payload->event_falling_edge	= gpio_resp->gpio_evt_fall;
+
+		if (copy_to_user((void *)arg, (void *)&buffer,
+					sizeof(struct gpio_buffer))) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+		}
+	} else {
+		if (copy_to_user((void *)arg, (void *)&buffer.header,
+					sizeof(struct ioctl_header))) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+		}
+	}
+exit:
+	spin_lock_irq(&pm8001_ha->ioctl_lock);
+	pm8001_ha->ioctl_completion = NULL;
+	spin_unlock_irq(&pm8001_ha->ioctl_lock);
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+	return ret;
+}
+
 static int pm8001_ioctl_get_phy_profile(struct pm8001_hba_info *pm8001_ha,
 		unsigned long arg)
 {
@@ -1100,6 +1168,9 @@ static long pm8001_ioctl(struct file *file,
 	case ADPT_IOCTL_INFO:
 		ret = pm8001_info_ioctl(pm8001_ha, arg);
 		break;
+	case ADPT_IOCTL_GPIO:
+		ret = pm8001_gpio_ioctl(pm8001_ha, arg);
+		break;
 	case ADPT_IOCTL_GET_PHY_PROFILE:
 		ret = pm8001_ioctl_get_phy_profile(pm8001_ha, arg);
 		return ret;
@@ -1122,11 +1193,35 @@ static long pm8001_ioctl(struct file *file,
 	return ret;
 }
 
+/**
+ *pm8001_poll - pm8001 poll request function
+ *@file: file handle
+ *@wait: poll table to wait
+ *Handles a poll request.
+ */
+__poll_t pm8001_poll(struct file *file, poll_table *wait)
+{
+	struct pm8001_hba_info *pm8001_ha;
+	__poll_t mask = 0;
+
+	pm8001_ha = file->private_data;
+
+	poll_wait(file, &pm8001_ha->pollq,  wait);
+
+	if (pm8001_ha->gpio_event_occurred == 1) {
+		pm8001_ha->gpio_event_occurred = 0;
+		mask |= POLLIN | POLLRDNORM;
+	}
+
+	return mask;
+}
+
 static const struct file_operations pm8001_fops = {
 	.owner		= THIS_MODULE,
 	.open		= pm8001_open,
 	.release	= pm8001_close,
 	.unlocked_ioctl	= pm8001_ioctl,
+	.poll		= pm8001_poll,
 };
 
 /**
drivers/scsi/pm8001/pm8001_ctl.h +24 -0
index 686ad69f0e0c..5be43b2672d4 100644
@@ -64,6 +64,7 @@
 #define ADPT_IOCTL_CALL_FAILED		0x01
 #define ADPT_IOCTL_CALL_INVALID_CODE	0x03
 #define ADPT_IOCTL_CALL_INVALID_DEVICE	0x04
+#define ADPT_IOCTL_CALL_TIMEOUT		0x08
 
 #define MAX_NUM_PHYS			16
 
@@ -86,11 +87,33 @@ struct ioctl_drv_info {
 	u32	reserved[16];
 };
 
+#define	GPIO_READ	0
+#define	GPIO_WRITE	1
+#define	GPIO_PINSETUP	2
+#define	GPIO_EVENTSETUP	3
+
+struct pm8001_gpio {
+	u32	operation;
+	u32	mask;
+	u32	rd_wr_val;
+	u32	input_enable;
+	u32	pinsetup1;
+	u32	pinsetup2;
+	u32	event_level;
+	u32	event_rising_edge;
+	u32	event_falling_edge;
+};
+
 struct ioctl_info_buffer {
 	struct ioctl_header	header;
 	struct ioctl_drv_info	information;
 };
 
+struct gpio_buffer {
+	struct ioctl_header	header;
+	struct pm8001_gpio	gpio_payload;
+};
+
 struct phy_profile {
 	char		phy_id;
 	unsigned int	phys:4;
@@ -119,6 +142,7 @@ struct phy_prof_resp {
 };
 
 #define ADPT_IOCTL_INFO _IOR(ADPT_MAGIC_NUMBER, 0, struct ioctl_info_buffer *)
+#define ADPT_IOCTL_GPIO	_IOWR(ADPT_MAGIC_NUMBER, 1, struct  gpio_buffer *)
 #define ADPT_IOCTL_GET_PHY_PROFILE _IOWR(ADPT_MAGIC_NUMBER, 8, \
 		struct phy_profile*)
 #define ADPT_IOCTL_GET_PHY_ERR_CNT _IOWR(ADPT_MAGIC_NUMBER, 9, \
drivers/scsi/pm8001/pm8001_init.c +6 -0
index 25e74f1dbd0c..6e2512aa5f6e 100644
@@ -498,6 +498,12 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
 	else
 		pm8001_ha->iomb_size = IOMB_SIZE_SPC;
 
+	mutex_init(&pm8001_ha->ioctl_mutex);
+	pm8001_ha->ioctl_completion = NULL;
+	init_waitqueue_head(&pm8001_ha->pollq);
+	pm8001_ha->gpio_event_occurred = 0;
+	spin_lock_init(&pm8001_ha->ioctl_lock);
+
 #ifdef PM8001_USE_TASKLET
 	/* Tasklet for non msi-x interrupt handler */
 	if ((!pdev->msix_cap || !pci_msi_enabled())
drivers/scsi/pm8001/pm8001_sas.h +17 -0
index 87d676810a18..7d9920376fb7 100644
@@ -132,6 +132,18 @@ extern const struct pm8001_dispatch pm8001_80xx_dispatch;
 struct pm8001_hba_info;
 struct pm8001_ccb_info;
 struct pm8001_device;
+
+struct gpio_ioctl_resp {
+	u32	tag;
+	u32	gpio_rd_val;
+	u32	gpio_in_enabled;
+	u32	gpio_pinsetup1;
+	u32	gpio_pinsetup2;
+	u32	gpio_evt_change;
+	u32	gpio_evt_rise;
+	u32	gpio_evt_fall;
+};
+
 /* define task management IU */
 struct pm8001_tmf_task {
 	u8	tmf;
@@ -247,6 +259,8 @@ struct pm8001_dispatch {
 	int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha,
 		u32 state);
 	int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
+	int (*gpio_req)(struct pm8001_hba_info *pm8001_ha,
+		struct pm8001_gpio *gpio_payload);
 	int (*get_phy_profile_req)(struct pm8001_hba_info *pm8001_ha,
 		int phy, int page);
 };
@@ -562,6 +576,9 @@ struct pm8001_hba_info {
 	u32			smp_exp_mode;
 	bool			controller_fatal_error;
 	const struct firmware 	*fw_image;
+	struct			gpio_ioctl_resp  gpio_resp;
+	u32			gpio_event_occurred;
+	wait_queue_head_t	pollq;
 	struct isr_param irq_vector[PM8001_MAX_MSIX_VEC];
 	spinlock_t		ioctl_lock;
 	struct mutex		ioctl_mutex;
drivers/scsi/pm8001/pm80xx_hwi.c +106 -0

133 lines not on this page · raw message

drivers/scsi/pm8001/pm80xx_hwi.h +49 -0

55 lines not on this page · raw message

Signature · 1 line
2.16.3
#32 lore raw

PATCH v2 10/13 pm80xx : IOCTL functionality for SGPIO.

In reply to Deepak Ukey

From: Deepak Ukey <[email protected]>

Added the IOCTL functionality for SGPIO through which management utility can controls SGPIO LEDs on the enclosure of locally attached drives only. It is used to read from/write into SGPIO registers and sets one or more SGPIO registers.

---
 drivers/scsi/pm8001/pm8001_ctl.c  |  71 ++++++++++++++++
 drivers/scsi/pm8001/pm8001_ctl.h  |  72 ++++++++++++++++
 drivers/scsi/pm8001/pm8001_hwi.c  | 172 +++++++++++++++++++++++++++++++++++++-
 drivers/scsi/pm8001/pm8001_hwi.h  |  17 ++++
 drivers/scsi/pm8001/pm8001_init.c |   3 +
 drivers/scsi/pm8001/pm8001_sas.c  |  37 ++++++++
 drivers/scsi/pm8001/pm8001_sas.h  |  20 +++++
 drivers/scsi/pm8001/pm80xx_hwi.c  |   6 ++
 drivers/scsi/pm8001/pm80xx_hwi.h  |   3 +
 9 files changed, 400 insertions(+), 1 deletion(-)
drivers/scsi/pm8001/pm8001_ctl.c +71 -0
index cadb5be394b6..d557b423edf6 100644
@@ -1009,6 +1009,74 @@ static long pm8001_gpio_ioctl(struct pm8001_hba_info *pm8001_ha,
 	return ret;
 }
 
+static long pm8001_sgpio_ioctl(struct pm8001_hba_info *pm8001_ha,
+		unsigned long arg)
+{
+	struct sgpio_buffer buffer;
+	struct read_write_req_resp *req = &buffer.sgpio_req;
+	struct sgpio_req payload;
+	struct sgpio_ioctl_resp *sgpio_resp;
+	DECLARE_COMPLETION_ONSTACK(completion);
+	unsigned long timeout;
+	u32 ret = 0, i;
+
+	if (copy_from_user(&buffer, (struct sgpio_buffer *)arg,
+		sizeof(struct sgpio_buffer))) {
+		return ADPT_IOCTL_CALL_FAILED;
+	}
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+	pm8001_ha->ioctl_completion = &completion;
+
+	payload.func_reg_index = cpu_to_le32((req->register_index << 24) |
+			(req->register_type << 16) | (req->function << 8) |
+			SMP_FRAME_REQ);
+	payload.count = req->register_count;
+
+	if (req->function == WRITE_SGPIO_REGISTER) {
+		if (req->register_count > MAX_SGPIO_REQ_PAYLOAD) {
+			ret = ADPT_IOCTL_CALL_FAILED;
+			goto exit;
+		}
+		for (i = 0; i < req->register_count; i++)
+			payload.value[i] = req->read_write_data[i];
+	}
+
+	ret = PM8001_CHIP_DISP->sgpio_req(pm8001_ha, &payload);
+	if (ret != 0) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+		goto exit;
+	}
+
+	timeout = wait_for_completion_timeout(&completion,
+			msecs_to_jiffies(2000));
+	if (timeout == 0) {
+		ret = ADPT_IOCTL_CALL_TIMEOUT;
+		goto exit;
+	}
+
+	sgpio_resp = &pm8001_ha->sgpio_resp;
+	req->frame_type		= sgpio_resp->func_result & 0xff;
+	req->function		= (sgpio_resp->func_result >> 8) & 0xff;
+	req->function_result	= (sgpio_resp->func_result >> 16) & 0xff;
+	if (req->function == READ_SGPIO_REGISTER) {
+		for (i = 0; i < req->register_count; i++)
+			req->read_write_data[i] = sgpio_resp->value[i];
+	}
+	ret = ADPT_IOCTL_CALL_SUCCESS;
+exit:
+	spin_lock_irq(&pm8001_ha->ioctl_lock);
+	pm8001_ha->ioctl_completion = NULL;
+	spin_unlock_irq(&pm8001_ha->ioctl_lock);
+	buffer.header.return_code = ret;
+	if (copy_to_user((void *)arg, (void *)&buffer,
+			sizeof(struct sgpio_buffer))) {
+		ret = ADPT_IOCTL_CALL_FAILED;
+	}
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+
+	return ret;
+}
+
 static int pm8001_ioctl_get_phy_profile(struct pm8001_hba_info *pm8001_ha,
 		unsigned long arg)
 {
@@ -1171,6 +1239,9 @@ static long pm8001_ioctl(struct file *file,
 	case ADPT_IOCTL_GPIO:
 		ret = pm8001_gpio_ioctl(pm8001_ha, arg);
 		break;
+	case ADPT_IOCTL_SGPIO:
+		ret = pm8001_sgpio_ioctl(pm8001_ha, arg);
+		break;
 	case ADPT_IOCTL_GET_PHY_PROFILE:
 		ret = pm8001_ioctl_get_phy_profile(pm8001_ha, arg);
 		return ret;
drivers/scsi/pm8001/pm8001_ctl.h +72 -0

96 lines not on this page · raw message

drivers/scsi/pm8001/pm8001_hwi.c +171 -1

206 lines not on this page · raw message

drivers/scsi/pm8001/pm8001_hwi.h +17 -0
index 6d91e2446542..aad2322467d2 100644
@@ -82,6 +82,7 @@
 #define OPC_INB_GET_DEVICE_STATE		43	/* 0x02B */
 #define OPC_INB_SET_DEV_INFO			44	/* 0x02C */
 #define OPC_INB_SAS_RE_INITIALIZE		45	/* 0x02D */
+#define OPC_INB_SGPIO_REG			46	/* 0x02E */
 
 /* for Response Opcode of IOMB */
 #define OPC_OUB_ECHO				1	/* 0x001 */
@@ -120,6 +121,7 @@
 #define OPC_OUB_GET_DEVICE_STATE		39	/* 0x027 */
 #define OPC_OUB_SET_DEV_INFO			40	/* 0x028 */
 #define OPC_OUB_SAS_RE_INITIALIZE		41	/* 0x029 */
+#define OPC_OUB_SGPIO_RESP			2094	/* 0x82E */
 
 /* for phy start*/
 #define SPINHOLD_DISABLE		(0x00 << 14)
@@ -697,6 +699,18 @@ struct set_dev_state_resp {
 	u32		reserved[11];
 } __attribute__((packed, aligned(4)));
 
+struct sgpio_reg_req {
+	__le32		tag;
+	__le32		func_reg_index;
+	__le32		count;
+	__le32		value[12];
+} __packed __aligned(4);
+
+struct sgpio_reg_resp {
+	__le32		tag;
+	__le32		func_result;
+	__le32		value[13];
+} __packed __aligned(4);
 
 #define NDS_BITS 0x0F
 #define PDS_BITS 0xF0
@@ -922,6 +936,9 @@ struct set_dev_state_resp {
 #define MAIN_HDA_FLAGS_OFFSET		0x84/* DWORD 0x21 */
 #define MAIN_ANALOG_SETUP_OFFSET	0x88/* DWORD 0x22 */
 
+/*FATAL ERROR INTERRUPT bit definition*/
+#define MAIN_CFG_SGPIO_ENABLE		(0x1 << 2)
+
 /* Gereral Status Table offset - byte offset */
 #define GST_GSTLEN_MPIS_OFFSET		0x00
 #define GST_IQ_FREEZE_STATE0_OFFSET	0x04
drivers/scsi/pm8001/pm8001_init.c +3 -0
index 6e2512aa5f6e..c8414f1b9652 100644
@@ -122,6 +122,7 @@ static struct sas_domain_function_template pm8001_transport_ops = {
 	.lldd_I_T_nexus_reset   = pm8001_I_T_nexus_reset,
 	.lldd_lu_reset		= pm8001_lu_reset,
 	.lldd_query_task	= pm8001_query_task,
+	.lldd_write_gpio	= pm8001_write_sgpio,
 };
 
 /**
@@ -1110,6 +1111,8 @@ static int pm8001_pci_probe(struct pci_dev *pdev,
 	if (pm8001_configure_phy_settings(pm8001_ha))
 		goto err_out_shost;
 
+	pm8001_setup_sgpio(pm8001_ha);
+
 	pm8001_post_sas_ha_init(shost, chip);
 	rc = sas_register_ha(SHOST_TO_SAS_HA(shost));
 	if (rc) {
drivers/scsi/pm8001/pm8001_sas.c +37 -0
index b7cbc312843e..1d03c62d8c99 100644
@@ -1361,3 +1361,40 @@ int pm8001_clear_task_set(struct domain_device *dev, u8 *lun)
 	return pm8001_issue_ssp_tmf(dev, lun, &tmf_task);
 }
 
+int pm8001_write_sgpio(struct sas_ha_struct *sas_ha, u8 reg_type,
+			u8 reg_index, u8 reg_count, u8 *write_data)
+{
+	struct pm8001_hba_info *pm8001_ha = sas_ha->lldd_ha;
+	struct sgpio_req payload;
+	u32 ret = 0, i, j, value;
+
+	PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+		"reg_type=%x, reg_index:%x, reg_count:%x\n",
+		reg_type, reg_index, reg_count));
+
+	mutex_lock(&pm8001_ha->ioctl_mutex);
+
+	payload.func_reg_index = cpu_to_le32((reg_index << 24) |
+		(reg_type << 16) | (WRITE_SGPIO_REGISTER << 8) |
+		SMP_FRAME_REQ);
+
+	payload.count = reg_count;
+
+	for (i = 0; i < reg_count; i++) {
+		value = 0;
+		for (j = 0; j < 4; j++) {
+			value |= (u32)(*write_data) << (24-(j*8));
+			write_data++;
+		}
+		payload.value[i] = value;
+		PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+			"payload value: %x\n", payload.value[i]));
+	}
+
+	ret = PM8001_CHIP_DISP->sgpio_req(pm8001_ha, &payload);
+	if (ret != 0)
+		ret = -1;
+
+	mutex_unlock(&pm8001_ha->ioctl_mutex);
+	return ret;
+}
drivers/scsi/pm8001/pm8001_sas.h +20 -0
index 7d9920376fb7..4c6c7d86f75e 100644
@@ -144,6 +144,17 @@ struct gpio_ioctl_resp {
 	u32	gpio_evt_fall;
 };
 
+struct sgpio_req {
+	u32	func_reg_index;
+	u32	count;
+	u32	value[MAX_SGPIO_REQ_PAYLOAD];
+};
+
+struct sgpio_ioctl_resp {
+	u32	func_result;
+	u32	value[MAX_SGPIO_RESP_PAYLOAD];
+};
+
 /* define task management IU */
 struct pm8001_tmf_task {
 	u8	tmf;
@@ -261,6 +272,8 @@ struct pm8001_dispatch {
 	int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha);
 	int (*gpio_req)(struct pm8001_hba_info *pm8001_ha,
 		struct pm8001_gpio *gpio_payload);
+	int (*sgpio_req)(struct pm8001_hba_info *pm8001_ha,
+		struct sgpio_req *sgpio_payload);
 	int (*get_phy_profile_req)(struct pm8001_hba_info *pm8001_ha,
 		int phy, int page);
 };
@@ -583,6 +596,7 @@ struct pm8001_hba_info {
 	spinlock_t		ioctl_lock;
 	struct mutex		ioctl_mutex;
 	struct completion	*ioctl_completion;
+	struct			sgpio_ioctl_resp sgpio_resp;
 	struct	phy_prof_resp	phy_profile_resp;
 	u32			reset_in_progress;
 };
@@ -696,6 +710,8 @@ int pm8001_lu_reset(struct domain_device *dev, u8 *lun);
 int pm8001_I_T_nexus_reset(struct domain_device *dev);
 int pm8001_I_T_nexus_event_handler(struct domain_device *dev);
 int pm8001_query_task(struct sas_task *task);
+int pm8001_write_sgpio(struct sas_ha_struct *sas_ha, u8 reg_type,
+		u8 reg_index, u8 reg_count, u8 *write_data);
 void pm8001_open_reject_retry(
 	struct pm8001_hba_info *pm8001_ha,
 	struct sas_task *task_to_close,
@@ -731,6 +747,8 @@ int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha,
 				struct pm8001_device *pm8001_dev,
 				u8 flag, u32 task_tag, u32 cmd_tag);
 int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha, u32 device_id);
+int pm8001_chip_sgpio_req(struct pm8001_hba_info *pm8001_ha,
+		struct sgpio_req *sgpio_payload);
 void pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd);
 void pm8001_work_fn(struct work_struct *work);
 int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha,
@@ -752,6 +770,7 @@ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha,
 							void *piomb);
 int pm8001_mpi_general_event(struct pm8001_hba_info *pm8001_ha , void *piomb);
 int pm8001_mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb);
+int pm8001_sgpio_resp(struct pm8001_hba_info *pm8001_ha, void *piomb);
 struct sas_task *pm8001_alloc_task(void);
 void pm8001_task_done(struct sas_task *task);
 void pm8001_free_task(struct sas_task *task);
@@ -759,6 +778,7 @@ void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag);
 struct pm8001_device *pm8001_find_dev(struct pm8001_hba_info *pm8001_ha,
 					u32 device_id);
 int pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha);
+int pm8001_setup_sgpio(struct pm8001_hba_info *pm8001_ha);
 
 int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
 void pm8001_set_phy_profile(struct pm8001_hba_info *pm8001_ha,
drivers/scsi/pm8001/pm80xx_hwi.c +6 -0
index 2cdcb1c64970..e4746fd9c09f 100644
@@ -4100,6 +4100,11 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb)
 			"OPC_OUB_SSP_COALESCED_COMP_RESP opcode:%x\n", opc));
 		ssp_coalesced_comp_resp(pm8001_ha, piomb);
 		break;
+	case OPC_OUB_SGPIO_RESP:
+		PM8001_MSG_DBG(pm8001_ha, pm8001_printk(
+			"OPC_OUB_SGPIO RESPONSE opcode: %x\n", opc));
+		pm8001_sgpio_resp(pm8001_ha, piomb);
+		break;
 	default:
 		PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(
 			"Unknown outbound Queue IOMB OPC = 0x%x\n", opc));
@@ -5170,5 +5175,6 @@ const struct pm8001_dispatch pm8001_80xx_dispatch = {
 	.fw_flash_update_req	= pm8001_chip_fw_flash_update_req,
 	.set_dev_state_req	= pm8001_chip_set_dev_state_req,
 	.gpio_req		= pm80xx_chip_gpio_req,
+	.sgpio_req		= pm8001_chip_sgpio_req,
 	.get_phy_profile_req	= pm8001_chip_get_phy_profile,
 };
drivers/scsi/pm8001/pm80xx_hwi.h +3 -0
index fed193df93d6..2d7f67b1cd93 100644
@@ -1509,6 +1509,9 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t;
 #define MAIN_MPI_ILA_RELEASE_TYPE	0xA4 /* DWORD 0x29 */
 #define MAIN_MPI_INACTIVE_FW_VERSION	0XB0 /* DWORD 0x2C */
 
+/*FATAL ERROR INTERRUPT bit definition*/
+#define MAIN_CFG_SGPIO_ENABLE		(0x1 << 2)
+
 /* Gereral Status Table offset - byte offset */
 #define GST_GSTLEN_MPIS_OFFSET		0x00
 #define GST_IQ_FREEZE_STATE0_OFFSET	0x04
Signature · 1 line
2.16.3
maintainer
#33 lore raw

Re: [PATCH V2 10/13] pm80xx : IOCTL functionality for SGPIO.

Quoted 7 lines · Deepak Ukey

From: Deepak Ukey <[email protected]>

Added the IOCTL functionality for SGPIO through which management utility can controls SGPIO LEDs on the enclosure of locally attached drives only. It is used to read from/write into SGPIO registers and sets one or more SGPIO registers.

Hi,
Thanks for addressing my comments.
another question:
Is it enough to only hook lldd_write_gpio without IOCTL to control SGPIO LED?

Thanks

#34 lore raw

PATCH v2 11/13 pm80xx : sysfs attribute for non fatal dump.

In reply to Deepak Ukey

From: Deepak Ukey <[email protected]>

Added the sysfs attribute for non fatal log so that management utility can get the non fatal dump from driver. The non-fatal error is an error condition or abnormal behavior detected by the host, or detected and reported by the controller to the host.The non-fatal error does not stop the controller firmware and enables it to still respond to host requests. A typical example of a non-fatal error is an I/O timeout or an unusual error notification from the controller. Since the firmware is operational, the error dump information is pushed to host memory (by firmware) upon request from the host.

---
 drivers/scsi/pm8001/pm8001_ctl.c  |  45 +++++++++++++
 drivers/scsi/pm8001/pm8001_init.c |   1 +
 drivers/scsi/pm8001/pm8001_sas.h  |   4 ++
 drivers/scsi/pm8001/pm80xx_hwi.c  | 130 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 180 insertions(+)
drivers/scsi/pm8001/pm8001_ctl.c +45 -0
index d557b423edf6..9fce19024945 100644
@@ -577,6 +577,49 @@ static ssize_t pm8001_ctl_fatal_log_show(struct device *cdev,
 
 static DEVICE_ATTR(fatal_log, S_IRUGO, pm8001_ctl_fatal_log_show, NULL);
 
+/**
+ ** non_fatal_log_show - non fatal error logging
+ ** @cdev:pointer to embedded class device
+ ** @buf: the buffer returned
+ **
+ ** A sysfs 'read-only' shost attribute.
+ **/
+static ssize_t non_fatal_log_show(struct device *cdev,
+	struct device_attribute *attr, char *buf)
+{
+	u32 count;
+
+	count = pm80xx_get_non_fatal_dump(cdev, attr, buf);
+	return count;
+}
+static DEVICE_ATTR_RO(non_fatal_log);
+
+static ssize_t non_fatal_count_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;
+
+	return snprintf(buf, PAGE_SIZE, "%08x",
+			pm8001_ha->non_fatal_count);
+}
+
+static ssize_t non_fatal_count_store(struct device *cdev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	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;
+	int val = 0;
+
+	if (kstrtoint(buf, 16, &val) != 0)
+		return -EINVAL;
+
+	pm8001_ha->non_fatal_count = val;
+	return strlen(buf);
+}
+static DEVICE_ATTR_RW(non_fatal_count);
 
 /**
  ** pm8001_ctl_gsm_log_show - gsm dump collection
@@ -853,6 +896,8 @@ struct device_attribute *pm8001_host_attrs[] = {
 	&dev_attr_aap_log,
 	&dev_attr_iop_log,
 	&dev_attr_fatal_log,
+	&dev_attr_non_fatal_log,
+	&dev_attr_non_fatal_count,
 	&dev_attr_gsm_log,
 	&dev_attr_max_out_io,
 	&dev_attr_max_devices,
drivers/scsi/pm8001/pm8001_init.c +1 -0
index c8414f1b9652..b74282bc1ed0 100644
@@ -484,6 +484,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
 	pm8001_ha->shost = shost;
 	pm8001_ha->id = pm8001_id++;
 	pm8001_ha->logging_level = logging_level;
+	pm8001_ha->non_fatal_count = 0;
 	if (link_rate >= 1 && link_rate <= 15)
 		pm8001_ha->link_rate = (link_rate << 8);
 	else {
drivers/scsi/pm8001/pm8001_sas.h +4 -0
index 4c6c7d86f75e..ae5f880dd9bb 100644
@@ -599,6 +599,8 @@ struct pm8001_hba_info {
 	struct			sgpio_ioctl_resp sgpio_resp;
 	struct	phy_prof_resp	phy_profile_resp;
 	u32			reset_in_progress;
+	u32			non_fatal_count;
+	u32			non_fatal_read_length;
 };
 
 struct pm8001_work {
@@ -788,6 +790,8 @@ void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha,
 int pm80xx_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue);
 ssize_t pm80xx_get_fatal_dump(struct device *cdev,
 		struct device_attribute *attr, char *buf);
+ssize_t pm80xx_get_non_fatal_dump(struct device *cdev,
+		struct device_attribute *attr, char *buf);
 ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf);
 /* ctl shared API */
 extern struct device_attribute *pm8001_host_attrs[];
drivers/scsi/pm8001/pm80xx_hwi.c +130 -0

136 lines not on this page · raw message

Signature · 1 line
2.16.3
maintainer Acked-by on v2 11/13
#35 lore raw

Re: [PATCH V2 11/13] pm80xx : sysfs attribute for non fatal dump.

Quoted 13 lines · Deepak Ukey

From: Deepak Ukey <[email protected]>

Added the sysfs attribute for non fatal log so that management utility can get the non fatal dump from driver. The non-fatal error is an error condition or abnormal behavior detected by the host, or detected and reported by the controller to the host.The non-fatal error does not stop the controller firmware and enables it to still respond to host requests. A typical example of a non-fatal error is an I/O timeout or an unusual error notification from the controller. Since the firmware is operational, the error dump information is pushed to host memory (by firmware) upon request from the host.

Quoted 3 lines

Thanks

#36 lore raw

PATCH v2 12/13 pm80xx : Introduce read and write length for IOCTL payload structure.

In reply to Deepak Ukey

From: Viswas G <[email protected]>

Removed the common length and introduce read and write length for IOCTL payload structure.

---
 drivers/scsi/pm8001/pm8001_ctl.c  |  6 +++---
 drivers/scsi/pm8001/pm8001_hwi.c  | 22 +++++++++++-----------
 drivers/scsi/pm8001/pm8001_init.c | 12 ++++++------
 drivers/scsi/pm8001/pm8001_sas.h  |  3 ++-
 4 files changed, 22 insertions(+), 21 deletions(-)
drivers/scsi/pm8001/pm8001_ctl.c +3 -3
index 9fce19024945..887a15ee69f6 100644
@@ -486,7 +486,7 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,
 	pm8001_ha->nvmd_completion = &completion;
 	payload.minor_function = 7;
 	payload.offset = 0;
-	payload.length = 4096;
+	payload.rd_length = 4096;
 	payload.func_specific = kzalloc(4096, GFP_KERNEL);
 	if (!payload.func_specific)
 		return -ENOMEM;
@@ -697,7 +697,7 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)
 	payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
 	memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data,
 				pm8001_ha->fw_image->size);
-	payload->length = pm8001_ha->fw_image->size;
+	payload->wr_length = pm8001_ha->fw_image->size;
 	payload->id = 0;
 	payload->minor_function = 0x1;
 	pm8001_ha->nvmd_completion = &completion;
@@ -743,7 +743,7 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)
 					IOCTL_BUF_SIZE);
 		for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {
 			payload = (struct pm8001_ioctl_payload *)ioctlbuffer;
-			payload->length = 1024*16;
+			payload->wr_length = 1024*16;
 			payload->id = 0;
 			fwControl =
 			      (struct fw_control_info *)&payload->func_specific;
drivers/scsi/pm8001/pm8001_hwi.c +11 -11
index f9395d9fd530..16dc7a92ad68 100644
@@ -4841,7 +4841,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 	if (!fw_control_context)
 		return -ENOMEM;
 	fw_control_context->usrAddr = (u8 *)ioctl_payload->func_specific;
-	fw_control_context->len = ioctl_payload->length;
+	fw_control_context->len = ioctl_payload->rd_length;
 	circularQ = &pm8001_ha->inbnd_q_tbl[0];
 	memset(&nvmd_req, 0, sizeof(nvmd_req));
 	rc = pm8001_tag_alloc(pm8001_ha, &tag);
@@ -4862,7 +4862,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 
 		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 |
 			twi_page_size << 8 | TWI_DEVICE);
-		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
 		nvmd_req.resp_addr_hi =
 		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
 		nvmd_req.resp_addr_lo =
@@ -4871,7 +4871,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 	}
 	case C_SEEPROM: {
 		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM);
-		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
 		nvmd_req.resp_addr_hi =
 		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
 		nvmd_req.resp_addr_lo =
@@ -4880,7 +4880,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 	}
 	case VPD_FLASH: {
 		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH);
-		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
 		nvmd_req.resp_addr_hi =
 		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
 		nvmd_req.resp_addr_lo =
@@ -4889,7 +4889,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 	}
 	case EXPAN_ROM: {
 		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM);
-		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
 		nvmd_req.resp_addr_hi =
 		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
 		nvmd_req.resp_addr_lo =
@@ -4898,7 +4898,7 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 	}
 	case IOP_RDUMP: {
 		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | IOP_RDUMP);
-		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->rd_length);
 		nvmd_req.vpd_offset = cpu_to_le32(ioctl_payload->offset);
 		nvmd_req.resp_addr_hi =
 		cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
@@ -4938,7 +4938,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 	circularQ = &pm8001_ha->inbnd_q_tbl[0];
 	memcpy(pm8001_ha->memoryMap.region[NVMD].virt_ptr,
 		&ioctl_payload->func_specific,
-		ioctl_payload->length);
+		ioctl_payload->wr_length);
 	memset(&nvmd_req, 0, sizeof(nvmd_req));
 	rc = pm8001_tag_alloc(pm8001_ha, &tag);
 	if (rc) {
@@ -4957,7 +4957,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
 		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 |
 			twi_page_size << 8 | TWI_DEVICE);
-		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
 		nvmd_req.resp_addr_hi =
 		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
 		nvmd_req.resp_addr_lo =
@@ -4966,7 +4966,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 	}
 	case C_SEEPROM:
 		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM);
-		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
 		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
 		nvmd_req.resp_addr_hi =
 		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
@@ -4975,7 +4975,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 		break;
 	case VPD_FLASH:
 		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH);
-		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
 		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
 		nvmd_req.resp_addr_hi =
 		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
@@ -4984,7 +4984,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha,
 		break;
 	case EXPAN_ROM:
 		nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM);
-		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length);
+		nvmd_req.resp_len = cpu_to_le32(ioctl_payload->wr_length);
 		nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98);
 		nvmd_req.resp_addr_hi =
 		    cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi);
drivers/scsi/pm8001/pm8001_init.c +6 -6
index b74282bc1ed0..6e037638656d 100644
@@ -643,22 +643,22 @@ static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha)
 	if (pm8001_ha->chip_id == chip_8001) {
 		if (deviceid == 0x8081 || deviceid == 0x0042) {
 			payload.minor_function = 4;
-			payload.length = 4096;
+			payload.rd_length = 4096;
 		} else {
 			payload.minor_function = 0;
-			payload.length = 128;
+			payload.rd_length = 128;
 		}
 	} else if ((pm8001_ha->chip_id == chip_8070 ||
 			pm8001_ha->chip_id == chip_8072) &&
 			pm8001_ha->pdev->subsystem_vendor == PCI_VENDOR_ID_ATTO) {
 		payload.minor_function = 4;
-		payload.length = 4096;
+		payload.rd_length = 4096;
 	} else {
 		payload.minor_function = 1;
-		payload.length = 4096;
+		payload.rd_length = 4096;
 	}
 	payload.offset = 0;
-	payload.func_specific = kzalloc(payload.length, GFP_KERNEL);
+	payload.func_specific = kzalloc(payload.rd_length, GFP_KERNEL);
 	if (!payload.func_specific) {
 		PM8001_INIT_DBG(pm8001_ha, pm8001_printk("mem alloc fail\n"));
 		return;
@@ -728,7 +728,7 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha)
 	/* SAS ADDRESS read from flash / EEPROM */
 	payload.minor_function = 6;
 	payload.offset = 0;
-	payload.length = 4096;
+	payload.rd_length = 4096;
 	payload.func_specific = kzalloc(4096, GFP_KERNEL);
 	if (!payload.func_specific)
 		return -ENOMEM;
drivers/scsi/pm8001/pm8001_sas.h +2 -1
index ae5f880dd9bb..13d7813b8d74 100644
@@ -164,10 +164,11 @@ struct pm8001_ioctl_payload {
 	u32	signature;
 	u16	major_function;
 	u16	minor_function;
-	u16	length;
 	u16	status;
 	u16	offset;
 	u16	id;
+	u32	wr_length;
+	u32	rd_length;
 	u8	*func_specific;
 };
 
Signature · 1 line
2.16.3
#37 lore raw

PATCH v2 13/13 pm80xx : IOCTL functionality for TWI device.

In reply to Deepak Ukey

From: Deepak Ukey <[email protected]>

Added the IOCTL functionality for TWI device so that management utility can manage the TWI device attached to the controller's TWI. The TWI device includes (but not limited to) the SEEPROM device. When NVME field set to 0000b (TWI devices), this command also allows the host to specify:
a. TWI device address
b. TWI Bus number
c. TWI device page size (1, 8, 16 or 32 bytes)
d. TWI device address size (1 or 2 bytes)
Also added the module parameter for TWI device address and page size in order to add support for different TWI devices.

---
 drivers/scsi/pm8001/pm8001_ctl.c  | 133 ++++++++++++++++++++++++++++++++++++++
 drivers/scsi/pm8001/pm8001_ctl.h  |  23 +++++++
 drivers/scsi/pm8001/pm8001_hwi.c  | 113 ++++++++++++++++++++++++++------
 drivers/scsi/pm8001/pm8001_hwi.h  |   1 +
 drivers/scsi/pm8001/pm8001_init.c |  10 +++
 drivers/scsi/pm8001/pm8001_sas.h  |  13 ++++
 drivers/scsi/pm8001/pm80xx_hwi.c  |  41 ++++++++++++
 drivers/scsi/pm8001/pm80xx_hwi.h  |   1 +
 8 files changed, 314 insertions(+), 21 deletions(-)
drivers/scsi/pm8001/pm8001_ctl.c +133 -0
index 887a15ee69f6..ce9d1ee5e995 100644
@@ -1122,6 +1122,126 @@ static long pm8001_sgpio_ioctl(struct pm8001_hba_info *pm8001_ha,
 	return ret;
 }
 
+static int icotl_twi_wr_request(int twi_wr,
+			struct pm8001_hba_info *pm8001_ha, unsigned long arg)
+{
+	int ret = 0;
+	unsigned char *buf;
+	int bus;
+	int addr;
+	bool addr_mode_7bit = true;
+	int rd_size = 0;
+	int wr_size = 0;
+	int offset = 0;
+	bool direct_addr  = true;
+	struct twi_ioctl_payload *twi_ioctl;
+
+	twi_ioctl = kmalloc(sizeof(struct twi_ioctl_payload), GFP_KERNEL);
+	if (!twi_ioctl) {
+		PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("Failed to allocate ioctl\n"));
+		return -ENOMEM;
+	}
+	ret = copy_from_user(twi_ioctl, (u8 *)arg, sizeof(*twi_ioctl));
+	if (ret) {
+		PM8001_FAIL_DBG(pm8001_ha,
+			pm8001_printk("Failed to get ioctl args\n"));
+		return -EIO;
+	}
+
+	bus = twi_ioctl->bus;
+	addr = twi_ioctl->addr;
+
+	switch (twi_wr) {
+	case TW_WRITE:
+		wr_size = twi_ioctl->wr_size;
+		/* first 1K read/write is not possible,
+		 * from 2k we have customer specific seeprom
+		 */
+		offset = twi_ioctl->offset;
+		if (wr_size > 48)
+			direct_addr = false;
+		buf = kzalloc(wr_size, GFP_KERNEL);
+
+		if (buf == NULL) {
+			PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("No Memory for write\n"));
+			return -ENOMEM;
+		}
+		ret = copy_from_user(buf, (u8 *)twi_ioctl->buf, wr_size);
+		if (!ret) {
+			ret = pm80xx_twi_wr_request(pm8001_ha, bus, addr,
+				addr_mode_7bit, rd_size, wr_size, offset,
+				direct_addr, buf);
+		} else {
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk
+				("Failed to get data from buffer\n"));
+			return -EIO;
+		}
+		kfree(buf);
+		break;
+	case TW_READ:
+		rd_size = twi_ioctl->rd_size;
+		offset = twi_ioctl->offset;
+		if (rd_size > 48)
+			direct_addr = false;
+		buf = kzalloc(rd_size, GFP_KERNEL);
+		if (buf == NULL) {
+			PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("No Memory for read\n"));
+			return -ENOMEM;
+		}
+		ret = pm80xx_twi_wr_request(pm8001_ha, bus, addr,
+			addr_mode_7bit, rd_size, wr_size, offset,
+			direct_addr, buf);
+		if (!ret) {
+			ret = copy_to_user((u8 *)twi_ioctl->buf, buf, rd_size);
+			kfree(buf);
+		} else {
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk
+				("pm80xx_twi_wr_request failed !!!\n"));
+			return -EIO;
+		}
+		break;
+	case TW_WRITE_READ:
+		rd_size = twi_ioctl->rd_size;
+		wr_size = twi_ioctl->wr_size;
+		offset = twi_ioctl->offset;
+		if (wr_size > 48 || rd_size > 48)
+			direct_addr = false;
+		buf = kzalloc(max_t(int, wr_size, rd_size), GFP_KERNEL);
+		if (buf == NULL) {
+			PM8001_FAIL_DBG(pm8001_ha,
+				pm8001_printk("No Memory for read\n"));
+			return -ENOMEM;
+		}
+		ret = copy_from_user(buf, (u8 *)twi_ioctl->buf, wr_size);
+		if (!ret) {
+			ret = pm80xx_twi_wr_request(pm8001_ha, bus, addr,
+				addr_mode_7bit, rd_size, wr_size, offset,
+				direct_addr, buf);
+			if (!ret)
+				ret = copy_to_user((u8 *)twi_ioctl->buf,
+					buf, rd_size);
+			else {
+				PM8001_FAIL_DBG(pm8001_ha, pm8001_printk
+				("Failed to copy data to read buffer\n"));
+				ret = -EIO;
+			}
+		} else {
+			PM8001_FAIL_DBG(pm8001_ha, pm8001_printk
+				("Failed to get data from write buffer\n"));
+			return -ENOMEM;
+		}
+		break;
+	default:
+		PM8001_FAIL_DBG(pm8001_ha, pm8001_printk
+			("Invalid twi operation\n"));
+		return -EINVAL;
+	}
+	return ret;
+}
+
 static int pm8001_ioctl_get_phy_profile(struct pm8001_hba_info *pm8001_ha,
 		unsigned long arg)
 {
@@ -1274,6 +1394,7 @@ static long pm8001_ioctl(struct file *file,
 	u32 ret = -EACCES;
 	struct pm8001_hba_info *pm8001_ha;
 	struct ioctl_header header;
+	u8 twi_wr = 0;
 
 	pm8001_ha = file->private_data;
 
@@ -1293,6 +1414,18 @@ static long pm8001_ioctl(struct file *file,
 	case ADPT_IOCTL_GET_PHY_ERR_CNT:
 		ret = pm8001_ioctl_get_phy_err(pm8001_ha, arg);
 		break;
+	case ADPT_IOCTL_TWI_WRITE:
+		twi_wr = 0x01;
+		ret = icotl_twi_wr_request(twi_wr, pm8001_ha, arg);
+		return ret;
+	case ADPT_IOCTL_TWI_READ:
+		twi_wr = 0x02;
+		ret = icotl_twi_wr_request(twi_wr, pm8001_ha, arg);
+		return ret;
+	case ADPT_IOCTL_TWI_WRITE_READ:
+		twi_wr = 0x03;
+		ret = icotl_twi_wr_request(twi_wr, pm8001_ha, arg);
+		return ret;
 	default:
 		ret = ADPT_IOCTL_CALL_INVALID_CODE;
 	}
drivers/scsi/pm8001/pm8001_ctl.h +23 -0
index b1be0bc065d5..57bf597aa9c3 100644
@@ -101,6 +101,26 @@
 #define SGPIO_CMD_ERROR_WRONG_FRAME_REG_TYPE_REG_INDEX	0x1D
 #define SGPIO_CMD_ERROR_WRONG_ALL_HEADER_PARAMS		0x9D
 
+#define TWI_SEEPROM_BUS_NUMBER	0
+#define TWI_SEEPROM_DEV_ADDR	0xa0
+#define TWI_SEEPROM_READ_SIZE	1024
+#define TWI_SEEPROM_WRITE_SIZE	1024
+
+#define TW_IOCTL_STATUS_SUCCESS		0
+#define TW_IOCTL_STATUS_FAILURE		1
+#define TW_IOCTL_STATUS_WRONG_ADDR	0xA
+
+struct twi_ioctl_payload {
+	u32	bus;
+	u32	addr;
+	u32	rd_size;
+	u32	wr_size;
+	u32	offset;
+	u8	addr_mode;
+	u8	*buf;
+	u32	status;
+};
+
 struct ioctl_header {
 	u32 io_controller_num;
 	u32 length;
@@ -219,6 +239,9 @@ struct phy_prof_resp {
 		struct phy_profile*)
 #define ADPT_IOCTL_GET_PHY_ERR_CNT _IOWR(ADPT_MAGIC_NUMBER, 9, \
 		struct phy_err*)
+#define ADPT_IOCTL_TWI_READ _IOR('m', 10, char *)
+#define ADPT_IOCTL_TWI_WRITE _IOW('m', 11, char *)
+#define ADPT_IOCTL_TWI_WRITE_READ _IOWR('m', 12, char *)
 #define ADPT_MAGIC_NUMBER	'm'
 
 #endif /* PM8001_CTL_H_INCLUDED */
drivers/scsi/pm8001/pm8001_hwi.c +92 -21

160 lines not on this page · raw message

drivers/scsi/pm8001/pm8001_hwi.h +1 -0
index aad2322467d2..98e9ea6a4d6e 100644
@@ -634,6 +634,7 @@ struct set_nvm_data_req {
 	__le32	resp_addr_hi;
 	__le32	resp_len;
 	u32	reserved1;
+	__le32	tr_dl;
 } __attribute__((packed, aligned(4)));
 
 
drivers/scsi/pm8001/pm8001_init.c +10 -0
index 6e037638656d..61fb9f622a5d 100644
@@ -55,6 +55,14 @@ MODULE_PARM_DESC(link_rate, "Enable link rate.\n"
 		" 4: Link rate 6.0G\n"
 		" 8: Link rate 12.0G\n");
 
+static ulong twi_address = 0xa0;
+module_param(twi_address, ulong, 0644);
+MODULE_PARM_DESC(twi_address, "set the address of twi device.");
+
+static ulong twi_page_size;
+module_param(twi_page_size, ulong, 0644);
+MODULE_PARM_DESC(twi_page_size, "set the page size of twi device.");
+
 static struct scsi_transport_template *pm8001_stt;
 
 /**
@@ -484,6 +492,8 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev,
 	pm8001_ha->shost = shost;
 	pm8001_ha->id = pm8001_id++;
 	pm8001_ha->logging_level = logging_level;
+	pm8001_ha->twi_address = twi_address;
+	pm8001_ha->twi_page_size = twi_page_size;
 	pm8001_ha->non_fatal_count = 0;
 	if (link_rate >= 1 && link_rate <= 15)
 		pm8001_ha->link_rate = (link_rate << 8);
drivers/scsi/pm8001/pm8001_sas.h +13 -0
index 13d7813b8d74..9074c3a14120 100644
@@ -169,6 +169,9 @@ struct pm8001_ioctl_payload {
 	u16	id;
 	u32	wr_length;
 	u32	rd_length;
+	bool	twi_direct_addr;
+	u8	bus;
+	u8	twi_addr;
 	u8	*func_specific;
 };
 
@@ -586,6 +589,8 @@ struct pm8001_hba_info {
 #endif
 	u32			logging_level;
 	u32			link_rate;
+	u32			twi_address;
+	u32			twi_page_size;
 	u32			fw_status;
 	u32			smp_exp_mode;
 	bool			controller_fatal_error;
@@ -648,6 +653,11 @@ struct pm8001_fw_image_header {
 #define DS_IN_ERROR				0x04
 #define DS_NON_OPERATIONAL			0x07
 
+#define TR_MASK			0x60000000
+#define TW_WRITE		0x01
+#define TW_READ			0x02
+#define TW_WRITE_READ		0x03
+
 /**
  * brief param structure for firmware flash update.
  */
@@ -794,6 +804,9 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev,
 ssize_t pm80xx_get_non_fatal_dump(struct device *cdev,
 		struct device_attribute *attr, char *buf);
 ssize_t pm8001_get_gsm_dump(struct device *cdev, u32, char *buf);
+int pm80xx_twi_wr_request(struct pm8001_hba_info *pm8001_ha, int bus, int addr,
+		bool addr_mode_7bit, int rd_size, int wr_size,
+		int offset, bool direct_addr, unsigned char *buf);
 /* ctl shared API */
 extern struct device_attribute *pm8001_host_attrs[];
 
drivers/scsi/pm8001/pm80xx_hwi.c +41 -0

47 lines not on this page · raw message

drivers/scsi/pm8001/pm80xx_hwi.h +1 -0
index 2d7f67b1cd93..ba49d0abd6f4 100644
@@ -966,6 +966,7 @@ struct set_nvm_data_req {
 	__le32	resp_addr_hi;
 	__le32	resp_len;
 	u32	reserved1[17];
+	__le32	tr_dl;
 } __attribute__((packed, aligned(4)));
 
 /**
Signature · 1 line
2.16.3