[parisc-linux-cvs] Re: 2.4.17-pa17 PDC_INITIATOR support

Grant Grundler grundler@dsl2.external.hp.com
Wed, 30 Jan 2002 01:18:07 -0700


Grant Grundler wrote:
> Log message:
> 2.4.17-pa17 PDC_INITIATOR support
> Enables use of 50-pin SE port on C3000 and similar machines.
> WARNING: If you have a disk attached to the 50-pin SE port, the
> disk numbering will change! (hint: fixup /etc/fstab first)
> At least on the C3000, scsi0 is the SE SCSI port.


Index: Makefile
===================================================================
RCS file: /var/cvs/linux/Makefile,v
retrieving revision 1.254
diff -u -p -r1.254 Makefile
--- Makefile	2002/01/28 22:58:39	1.254
+++ Makefile	2002/01/30 08:01:50
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 17
-EXTRAVERSION = -pa16
+EXTRAVERSION = -pa17
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
Index: include/asm-parisc/hardware.h
===================================================================
RCS file: /var/cvs/linux/include/asm-parisc/hardware.h,v
retrieving revision 1.33
diff -u -p -r1.33 hardware.h
--- include/asm-parisc/hardware.h	2002/01/28 22:56:04	1.33
+++ include/asm-parisc/hardware.h	2002/01/30 08:01:51
@@ -147,6 +147,8 @@ extern void print_subdevices(struct pari
 extern void print_parisc_devices(void);
 extern char *print_pa_hwpath(struct parisc_device *dev, char *path);
 extern char *print_pci_hwpath(struct pci_dev *dev, char *path);
+extern void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path);
+
 
 /* inventory.c: */
 extern void do_memory_inventory(void);
Index: include/asm-parisc/pdc.h
===================================================================
RCS file: /var/cvs/linux/include/asm-parisc/pdc.h,v
retrieving revision 1.39
diff -u -p -r1.39 pdc.h
--- include/asm-parisc/pdc.h	2002/01/06 16:24:18	1.39
+++ include/asm-parisc/pdc.h	2002/01/30 08:01:52
@@ -147,8 +147,14 @@
 #define PDC_PCI_GET_INT_TBL_SIZE 13
 #define PDC_PCI_GET_INT_TBL	 14
 
+/* Get SCSI Interface Card info:  SDTR, SCSI ID, mode (SE vs LVD) */
+#define PDC_INITIATOR    163UL
+#define PDC_GET_INITIATOR    0UL
+#define PDC_SET_INITIATOR    1UL
+#define PDC_DELETE_INITIATOR 2UL
+#define PDC_RETURN_TABLE_SIZE 3UL
+#define PDC_RETURN_TABLE     4UL
 
-
 /* constants for OS (NVM...) */
 #define OS_ID_NONE		0
 #define OS_ID_HPUX		1
@@ -804,6 +810,7 @@ int pdc_lan_station_id(char *lan_addr, u
 int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa);
 int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl);
 
+int pdc_get_initiator(struct hardware_path *hwpath, unsigned char *scsi_id, unsigned long *period, char *width, char *mode);
 int pdc_tod_read(struct pdc_tod *tod);
 int pdc_tod_set(unsigned long sec, unsigned long usec);
 
Index: arch/parisc/kernel/firmware.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/firmware.c,v
retrieving revision 1.39
diff -u -p -r1.39 firmware.c
--- arch/parisc/kernel/firmware.c	2002/01/06 16:24:18	1.39
+++ arch/parisc/kernel/firmware.c	2002/01/30 08:01:52
@@ -45,10 +45,12 @@
 #include <linux/string.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 
 #include <asm/page.h>
 #include <asm/pdc.h>
 #include <asm/system.h>
+#include <asm/processor.h>	/* for boot_cpu_data */
 
 #include <stdarg.h>
 
@@ -478,7 +480,84 @@ int pdc_lan_station_id(char *lan_addr, u
 	return retval;
 }
 
+
 /**
+ * pdc_get_initiator - Get the SCSI Interface Card params (SCSI ID, SDTR, SE or LVD)
+ * @hwpath: fully bc.mod style path to the device.
+ * @scsi_id: what someone told firmware the ID should be.
+ * @period: time in cycles 
+ * @width: 8 or 16-bit wide bus
+ * @mode: 0,1,2 -> SE,HVD,LVD signalling mode
+ *
+ * Get the SCSI operational parameters from PDC.
+ * Needed since HPUX never used BIOS or symbios card NVRAM.
+ * Most ncr/sym cards won't have an entry and just use whatever
+ * capabilities of the card are (eg Ultra, LVD). But there are
+ * several cases where it's useful:
+ *    o set SCSI id for Multi-initiator clusters,
+ *    o cable too long (ie SE scsi 10Mhz won't support 6m length),
+ *    o bus width exported is less than what the interface chip supports.
+ */
+int pdc_get_initiator( struct hardware_path *hwpath, unsigned char *scsi_id,
+	unsigned long *period, char *width, char *mode)
+{
+	int retval;
+
+	spin_lock_irq(&pdc_lock);
+
+/* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */
+#define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \
+	strncmp(boot_cpu_data.pdc.sys_model_name, "9000/785", 9) == 0)
+
+	retval = mem_pdc_call(PDC_INITIATOR, PDC_GET_INITIATOR, 
+			      __pa(pdc_result), __pa(hwpath));
+
+
+	if (retval >= PDC_OK) {
+		*scsi_id = (unsigned char) pdc_result[0];
+
+		/* convert Bus speed in Mhz to period (in 1/10 ns) */
+		switch(pdc_result[1]) {
+		/*
+		** case  0:   driver determines rate
+		** case -1:   Settings are uninitialized.
+		*/
+		case  5:  *period = 2000; break;
+		case 10:  *period = 1000; break;
+		case 20:  *period = 500; break;
+		case 40:  *period = 250; break;
+		default: /* Do nothing */ break;
+		}
+
+		/* 
+		** pdc_result[2]	PDC suggested SCSI id
+		** pdc_result[3]	PDC suggested SCSI rate
+		*/
+
+		if (IS_SPROCKETS()) {
+			/*
+			** Revisit: PAT PDC do the same thing?
+			** A500 also exports 50-pin SE SCSI.
+			**	0 == 8-bit
+			**	1 == 16-bit
+			*/
+			*width = (char) pdc_result[4];
+
+			/* ...in case someone needs it in the future.
+			** sym53c8xx.c comments say it can't autodetect
+			** for 825/825A/875 chips.
+			**	0 == SE, 1 == HVD, 2 == LVD
+			*/
+			*mode = (char) pdc_result[5]; 
+		}
+	}
+
+	spin_unlock_irq(&pdc_lock);
+	return retval >= PDC_OK;
+}
+
+
+/**
  * pdc_pci_irt_size - Get the number of entries in the interrupt routing table.
  * @num_entries: The return value.
  * @hpa: The HPA for the device.
@@ -522,6 +601,7 @@ int pdc_pci_irt(unsigned long num_entrie
 
 	return retval;
 }
+
 
 /**
  * pdc_tod_read - Read the Time-Of-Day clock.
Index: arch/parisc/kernel/parisc_ksyms.c
===================================================================
RCS file: /var/cvs/linux/arch/parisc/kernel/parisc_ksyms.c,v
retrieving revision 1.38
diff -u -p -r1.38 parisc_ksyms.c
--- arch/parisc/kernel/parisc_ksyms.c	2002/01/21 00:15:15	1.38
+++ arch/parisc/kernel/parisc_ksyms.c	2002/01/30 08:01:52
@@ -26,8 +26,10 @@ EXPORT_SYMBOL(strtok);
 EXPORT_SYMBOL(strstr);
 
 #if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+#include <asm/hardware.h>	/* struct parisc_device for asm/pci.h */
 #include <linux/pci.h>
 EXPORT_SYMBOL(hppa_dma_ops);
+EXPORT_SYMBOL(get_pci_node_path);
 #endif
 
 #ifdef CONFIG_IOMMU_CCIO
@@ -146,6 +148,7 @@ EXPORT_SYMBOL(csum_partial_copy);
 #include <asm/pdc.h>
 EXPORT_SYMBOL(pdc_add_valid);
 EXPORT_SYMBOL(pdc_lan_station_id);
+EXPORT_SYMBOL(pdc_get_initiator);
 
 extern void $$divI(void);
 extern void $$divU(void);
Index: drivers/scsi/sym53c8xx.c
===================================================================
RCS file: /var/cvs/linux/drivers/scsi/sym53c8xx.c,v
retrieving revision 1.16
diff -u -p -r1.16 sym53c8xx.c
--- drivers/scsi/sym53c8xx.c	2002/01/03 22:37:18	1.16
+++ drivers/scsi/sym53c8xx.c	2002/01/30 08:01:59
@@ -4915,6 +4915,11 @@ static int __init ncr_prepare_setting(nc
 	u_long	period;
 	int i;
 
+#ifdef CONFIG_PARISC
+	char scsi_mode = -1;
+	struct hardware_path hwpath;
+#endif
+
 	/*
 	**	Wide ?
 	*/
@@ -4986,6 +4991,29 @@ static int __init ncr_prepare_setting(nc
 	 */
 
 	period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz;
+
+#if defined(CONFIG_PARISC)
+	/* Host firmware (PDC) keeps a table for crippling SCSI capabilities.
+	 * Many newer machines export one channel of 53c896 chip
+	 * as SE, 50-pin HD.  Also used for Multi-initiator SCSI clusters
+	 * to set the SCSI Initiator ID.
+	 */
+	get_pci_node_path(np->pdev, &hwpath);
+	if (pdc_get_initiator(&hwpath, &np->myaddr, &period, &np->maxwide, &scsi_mode))
+	{
+		if (scsi_mode >= 0) {
+			/* C3000 PDC reports period/mode */
+			driver_setup.diff_support = 0;
+			switch(scsi_mode) {
+			case 0:	np->scsi_mode = SMODE_SE; break;
+			case 1:	np->scsi_mode = SMODE_HVD; break;
+			case 2:	np->scsi_mode = SMODE_LVD; break;
+			default:	break;
+			}
+		}
+	}
+#endif
+
 	if	(period <= 250)		np->minsync = 10;
 	else if	(period <= 303)		np->minsync = 11;
 	else if	(period <= 500)		np->minsync = 12;
@@ -5128,7 +5156,6 @@ static int __init ncr_prepare_setting(nc
 		np->rv_ctest4	|= MPEE;	/* Master parity checking */
 	if (driver_setup.scsi_parity)
 		np->rv_scntl0	|= 0x0a;	/*  full arb., ena parity, par->ATN  */
-
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 	/*
 	**	Get parity checking, host ID and verbose mode from NVRAM
@@ -5196,7 +5223,7 @@ static int __init ncr_prepare_setting(nc
 			if (np->sv_stest2 & 0x20)
 				np->scsi_mode = SMODE_HVD;
 			break;
-		default:/* Don't care about HVD */	
+		default: /* Don't care about HVD */	
 			break;
 		}
 	}
@@ -5239,6 +5266,7 @@ static int __init ncr_prepare_setting(nc
 		tcb_p tp = &np->target[i];
 
 		tp->usrsync = 255;
+
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 		if (nvram) {
 			switch(nvram->type) {
@@ -5256,10 +5284,11 @@ static int __init ncr_prepare_setting(nc
 			if (driver_setup.use_nvram & 0x8)
 				tp->usrflag &= ~UF_NOSCAN;
 		}
-		else {
+		else
 #else
-		if (1) {
+		if (1) 
 #endif
+		{
 			tp->usrsync = driver_setup.default_sync;
 			tp->usrwide = driver_setup.max_wide;
 			tp->usrtags = MAX_TAGS;
@@ -7074,7 +7103,11 @@ static int ncr_reset_scsi_bus(ncb_p np, 
 		((INW(nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
 		INB(nc_sbcl);	/* req ack bsy sel atn msg cd io    */
 
+#ifdef CONFIG_PARISC
+	if (np->maxwide)
+#else
 	if (!(np->features & FE_WIDE))
+#endif
 		term &= 0x3ffff;
 
 	if (term != (2<<7)) {