All of lore.kernel.org
 help / color / mirror / Atom feed
* [ANNOUNCE] Adaptec SAS/SATA device driver [12/27]
@ 2005-02-17 17:36 Luben Tuikov
  0 siblings, 0 replies; only message in thread
From: Luben Tuikov @ 2005-02-17 17:36 UTC (permalink / raw)
  To: SCSI Mailing List

IOCTL code.

diff -Nru a/drivers/scsi/adp94xx/adp94xx_ioctl.c b/drivers/scsi/adp94xx/adp94xx_ioctl.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/drivers/scsi/adp94xx/adp94xx_ioctl.c	2005-02-16 16:08:12 -05:00
@@ -0,0 +1,1041 @@
+/*
+ * Adaptec ADP94xx SAS HBA driver for Linux - IOCTL interface for Linux.
+ *
+ * Written by : Naveen Chandrasekaran <naveen_chandrasekaran@adaptec.com>
+ * 
+ * Copyright (c) 2004-05 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/razor/linux/src/adp94xx_ioctl.c#10 $
+ *
+ */	
+
+#include "adp94xx_osm.h"
+#include "adp94xx_inline.h"
+#include "adp94xx_ioctl.h"
+
+#ifdef __x86_64__
+#include <asm/ioctl32.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 0)	
+#include <linux/syscalls.h>
+#endif
+#endif
+
+/* IOCTL control device name */
+#define ASD_CTL_DEV_NAME	"asdctl"
+static int asd_ctl_major;
+
+/* protos for char device entry points */
+static int asd_ctl_open(struct inode *inode, struct file *file);
+static int asd_ctl_close(struct inode *inode, struct file *file);
+static int asd_ctl_ioctl(struct inode *inode, struct file *file,
+			 unsigned int cmd, unsigned long arg);
+
+/* protos for ioctl handlers */
+static int asd_ctl_get_cntlr_config(unsigned long arg);
+
+/* protos for Adaptec NVRAM access ioctl handlers */
+static int asd_ctl_sas_get_adpt_cntlr_conf(unsigned long arg);
+static int asd_ctl_sas_get_nv_seg_prop(unsigned long arg);
+static int asd_ctl_sas_write_nv_seg(unsigned long arg);
+static int asd_ctl_sas_read_nv_seg(unsigned long arg);
+
+/* protos for helper - work horse routines for ioctl handlers */
+static int asd_ctl_write_to_nvram(struct asd_softc *asd,
+	struct ASD_SAS_WRITE_NV_SEGMENT_BUFFER *pasd_write_nv_buf,
+	uint8_t *psource_buffer);
+
+static int asd_ctl_read_from_nvram(struct asd_softc *asd,
+	struct ASD_SAS_READ_NV_SEGMENT_BUFFER *pasd_read_nv_buf,
+	uint8_t *pdest_buffer);
+
+static uint32_t asd_ctl_write_to_flash (struct asd_softc *asd, 
+			uint8_t *src_img_addr, uint32_t segment_id, 
+			uint32_t src_img_offset, uint32_t src_img_size);
+
+/* protos for extern routines */
+#ifdef __x86_64__
+extern int register_ioctl32_conversion(unsigned int cmd, 
+	int (*handler)(unsigned int, unsigned int, unsigned long,
+	struct file *));
+
+extern int unregister_ioctl32_conversion(unsigned int cmd); 
+#endif
+
+extern int asd_hwi_search_nv_cookie(struct asd_softc *asd, 
+			uint32_t *addr,
+			struct asd_flash_dir_layout *pflash_dir_buf);
+
+/* fops table */
+static struct file_operations asd_ctl_fops = {
+	.owner		= THIS_MODULE,
+	.open		= asd_ctl_open,
+	.release	= asd_ctl_close,
+	.ioctl		= asd_ctl_ioctl
+};
+
+/* macros */
+#define asd_valloc_mem(size)		vmalloc(size)
+#define asd_vfree_mem(ptr)		vfree(ptr)
+#define ASD_CTL_TIMEOUT(pioctl_header) 	\
+((pioctl_header->Timeout == 0? ASD_ADAPTEC_TIMEOUT: \
+				pioctl_header->Timeout) * HZ) 
+
+/* represents busy bit number */
+#define ASD_CTL_INTERNAL_BUSY_BIT_NR 0
+
+/* inline routines */
+/*
+ * Function:
+ * 	asd_ctl_check_buf_len()
+ *
+ * Description:
+ * 	This routine validates the buffer length specified in the CSMI
+ * 	IOCTL header with the actual size of the buffer needed for the 
+ * 	corresponding IOCTL.
+ */
+static inline int asd_ctl_check_buf_len(unsigned long arg, int buffer_length)
+{
+	struct IOCTL_HEADER ioctl_header;
+	int err;
+	
+	if ((err = copy_from_user(&ioctl_header, (void *)arg, 
+				 sizeof(ioctl_header)))) {
+		return -EFAULT;
+	}
+
+	if (ioctl_header.Length < buffer_length) {
+		ioctl_header.ReturnCode = ASD_SAS_STATUS_INVALID_PARAMETER;
+		if ((err = copy_to_user((void *)arg, &ioctl_header, 
+					sizeof(ioctl_header)))) {
+			return -EFAULT;
+		}
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static inline int asd_ctl_copy_to_user(void *dest, void *src, uint32_t length, 
+			uint32_t status)
+{
+	struct IOCTL_HEADER *pioctl_header;
+	int err;
+
+	pioctl_header = (struct IOCTL_HEADER *)src;
+	pioctl_header->ReturnCode = status;
+	if ((err = copy_to_user(dest, src, length))) {
+		return -EFAULT;
+	}
+	return 0;
+}
+
+static inline int asd_ctl_map_nv_segid_from_ext(uint32_t ext_segid, 
+			uint32_t *asd_segid)
+{
+	switch (ext_segid) {
+	case ASD_SAS_SEGMENT_ID_CTRL_A_USER_SETTINGS0:
+		*asd_segid = NVRAM_CTRL_A_SETTING;
+		break;
+	case ASD_SAS_SEGMENT_ID_MANUFACTURING_SECTOR0: 
+		*asd_segid = NVRAM_MANUF_TYPE;
+		break;
+	case ASD_SAS_SEGMENT_ID_FLASH_DIRECTORY0:/*TBD*/
+	case ASD_SAS_SEGMENT_ID_FLASH0:
+	case ASD_SAS_SEGMENT_ID_SEEPROM0:
+	case ASD_SAS_SEGMENT_ID_COMPATIBILITY_SECTOR0:
+		*asd_segid = NVRAM_NO_SEGMENT_ID;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+static inline int asd_ctl_map_seg_attr_to_ext(uint16_t asd_seg_attr, 
+			uint16_t *ext_seg_attr)
+{
+	switch (asd_seg_attr) {
+	case 0:
+		*ext_seg_attr = ASD_SAS_SEGMENT_ATTRIBUTE_READONLY;
+		break;	
+	case 1:
+		*ext_seg_attr = ASD_SAS_SEGMENT_ATTRIBUTE_ERASEWRITE;
+		break;
+	default:
+		return -1;
+	}
+	return 0;
+}
+
+/* registration routines */
+int asd_register_ioctl_dev(void)
+{
+	int err;
+	
+	err = 0;
+	asd_ctl_major = 0;
+
+	/* 
+	 * Register the IOCTL control device and request 
+	 * for a dynamic major number 
+	 */
+	if (!(asd_ctl_major = register_chrdev(0, ASD_CTL_DEV_NAME, 
+						&asd_ctl_fops))) {
+		return -ENODEV;
+	}
+
+#ifdef __x86_64__
+	/* 
+	 * This ioctl handler module is compatible between 64 and 32 bit
+	 * environments, hence register the default handler as 32bit 
+	 * ioctl conversion handler.
+	 */
+	err |= register_ioctl32_conversion(ASD_CC_SAS_GET_CNTLR_CONFIG, 
+							(void *)sys_ioctl);
+	err |= register_ioctl32_conversion(ASD_CC_SAS_GET_ADPT_CNTLR_CONFIG,
+							(void *)sys_ioctl);
+	err |= register_ioctl32_conversion(
+				ASD_CC_SAS_GET_NV_SEGMENT_PROPERTIES,
+							(void *)sys_ioctl);
+	err |= register_ioctl32_conversion(ASD_CC_SAS_WRITE_NV_SEGMENT,
+							(void *)sys_ioctl);
+	err |= register_ioctl32_conversion(ASD_CC_SAS_READ_NV_SEGMENT,
+							(void *)sys_ioctl);
+#endif /* #ifdef __x86_64__ */
+	return err;
+}
+
+int asd_unregister_ioctl_dev(void)
+{
+#ifdef __x86_64__
+	unregister_ioctl32_conversion(ASD_CC_SAS_GET_CNTLR_CONFIG);
+	unregister_ioctl32_conversion(ASD_CC_SAS_GET_ADPT_CNTLR_CONFIG);
+	unregister_ioctl32_conversion(ASD_CC_SAS_GET_NV_SEGMENT_PROPERTIES);
+	unregister_ioctl32_conversion(ASD_CC_SAS_WRITE_NV_SEGMENT);
+	unregister_ioctl32_conversion(ASD_CC_SAS_READ_NV_SEGMENT);
+#endif /* #ifdef __x86_64__ */
+
+	return unregister_chrdev(asd_ctl_major, ASD_CTL_DEV_NAME);
+}
+
+/* init routine */
+int asd_ctl_init_internal_data(struct asd_softc *asd)
+{
+	struct asd_ctl_mgmt *pasd_ctl_mgmt;
+	
+	pasd_ctl_mgmt = &asd->asd_ctl_internal.mgmt;
+	
+	/* Initialize waitq */
+	init_waitqueue_head(&pasd_ctl_mgmt->waitq);
+	
+	/* Initialize busy flags */
+	pasd_ctl_mgmt->busy = 0;
+	
+	/* Initialize semaphore */
+	init_MUTEX(&pasd_ctl_mgmt->sem);
+	
+	/* Initialize timers */
+	init_timer(&pasd_ctl_mgmt->timer);
+
+	/* Initialize err flag */
+	pasd_ctl_mgmt->err = SCB_EH_FAILED;
+	
+	return 0;
+}
+
+/* entry points */
+static int asd_ctl_open(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)	
+	MOD_INC_USE_COUNT;
+#endif	
+	return 0;
+}
+
+static int asd_ctl_close(struct inode *inode, struct file *file)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)	
+	MOD_DEC_USE_COUNT;
+#endif	
+	return 0;
+}
+
+static int asd_ctl_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct IOCTL_HEADER ioctl_header;
+	int asd_user_buf_len;
+	int hba, max_hba;
+	int err;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		return -EACCES;
+	}
+	
+	asd_user_buf_len = sizeof(ioctl_header);
+	if ((err = copy_from_user(&ioctl_header, (void *)arg, 
+				asd_user_buf_len))) {
+		return -EFAULT;
+	}
+
+	hba = ioctl_header.IOControllerNumber;
+
+	max_hba = asd_get_number_of_hbas_present();
+
+	if (hba < 0 || hba >= max_hba) {
+		asd_ctl_copy_to_user((void *)arg, 
+				     &ioctl_header, 
+				     asd_user_buf_len,
+				     ASD_SAS_STATUS_INVALID_PARAMETER);
+		return -ENODEV;
+	}
+
+	switch (cmd) {
+	case ASD_CC_SAS_GET_CNTLR_CONFIG:
+		err = asd_ctl_get_cntlr_config(arg);
+		break;
+	case ASD_CC_SAS_GET_ADPT_CNTLR_CONFIG:
+		err = asd_ctl_sas_get_adpt_cntlr_conf(arg);
+		break;
+	case ASD_CC_SAS_GET_NV_SEGMENT_PROPERTIES:
+		err = asd_ctl_sas_get_nv_seg_prop(arg);
+		break;
+	case ASD_CC_SAS_WRITE_NV_SEGMENT:
+		err = asd_ctl_sas_write_nv_seg(arg);
+		break;
+	case ASD_CC_SAS_READ_NV_SEGMENT:
+		err = asd_ctl_sas_read_nv_seg(arg);
+		break;
+	/* Unsupported/Unknown IOCTLs */
+	default:
+		asd_ctl_copy_to_user((void *)arg, 
+				     &ioctl_header, 
+				     asd_user_buf_len,
+				     ASD_SAS_STATUS_BAD_CNTL_CODE);
+		return -EINVAL;
+	}
+
+	return err;
+}
+
+
+/* ioctl handler routines */
+static int asd_ctl_get_cntlr_config(unsigned long arg)
+{
+	struct ASD_SAS_CNTLR_CONFIG_BUFFER asd_cntlr_conf_buf;
+	struct ASD_SAS_CNTLR_CONFIG *pasd_sas_cntlr_config;
+	union ASD_SAS_IO_BUS_ADDRESS *pasd_sas_io_bus_address;
+	struct ASD_SAS_PCI_BUS_ADDRESS *pasd_sas_pci_bus_address;
+	struct IOCTL_HEADER *pioctl_header;
+	struct asd_softc *asd;
+	int asd_user_buf_len;
+	int retcode;
+	int err;
+	
+	asd_user_buf_len = sizeof(asd_cntlr_conf_buf);
+	if ((err = asd_ctl_check_buf_len(arg, asd_user_buf_len))) {
+		return -EINVAL;
+	}
+	
+	if ((err = copy_from_user(&asd_cntlr_conf_buf, (void *)arg, 
+				  asd_user_buf_len))) {
+		return -EFAULT;
+	}
+	
+	pioctl_header = &asd_cntlr_conf_buf.IoctlHeader;
+	
+	asd = asd_get_softc_by_hba_index(pioctl_header->IOControllerNumber);
+	if (asd == NULL) {
+		/* Requested controller not found */
+		retcode = ASD_SAS_STATUS_INVALID_PARAMETER;
+		err = -ENODEV;
+		goto done;
+	}
+		
+	retcode = ASD_SAS_STATUS_SUCCESS;
+	err = 0;
+	pasd_sas_cntlr_config = &asd_cntlr_conf_buf.Configuration;
+	pasd_sas_io_bus_address = &pasd_sas_cntlr_config->BusAddress;
+	pasd_sas_pci_bus_address = &pasd_sas_io_bus_address->PciAddress;
+
+	pasd_sas_cntlr_config->uBaseIoAddress = 
+				asd_pcic_read_dword(asd, PCI_BASE_ADDRESS_0);
+	pasd_sas_cntlr_config->BaseMemoryAddress.uLowPart =
+				asd_pcic_read_dword(asd, PCI_BASE_ADDRESS_2);
+	pasd_sas_cntlr_config->BaseMemoryAddress.uHighPart =
+				asd_pcic_read_dword(asd, PCI_BASE_ADDRESS_3);
+
+	pasd_sas_cntlr_config->uBoardID =
+				(asd_pci_dev(asd)->device << 16) |
+				asd_pci_dev(asd)->vendor;
+
+	pasd_sas_cntlr_config->usSlotNumber = 
+				PCI_SLOT(asd_pci_dev(asd)->devfn);
+	pasd_sas_cntlr_config->bControllerClass = ASD_SAS_CNTLR_CLASS_HBA;
+	pasd_sas_cntlr_config->bIoBusType = ASD_SAS_BUS_TYPE_PCI;
+	pasd_sas_pci_bus_address->bBusNumber = asd_pci_dev(asd)->bus->number;
+	pasd_sas_pci_bus_address->bDeviceNumber =
+				PCI_SLOT(asd_pci_dev(asd)->devfn);
+	pasd_sas_pci_bus_address->bFunctionNumber =
+				PCI_FUNC(asd_pci_dev(asd)->devfn);
+	
+	sprintf(pasd_sas_cntlr_config->szSerialNumber,"%01x%06x%08x%x", 
+			ASD_BSAR_GET_NAA(asd->hw_profile.wwn), 
+			ASD_BSAR_GET_IEEE_ID(asd->hw_profile.wwn),
+			ASD_BSAR_GET_SN(asd->hw_profile.wwn),
+			ASD_BSAR_GET_LSB(asd->hw_profile.wwn));
+
+	pasd_sas_cntlr_config->usMajorRevision = 0;
+	pasd_sas_cntlr_config->usMinorRevision = 0;
+	pasd_sas_cntlr_config->usBuildRevision = 0;
+	pasd_sas_cntlr_config->usReleaseRevision = 0;
+	pasd_sas_cntlr_config->usBIOSMajorRevision = 
+				asd->hw_profile.bios_maj_ver; 
+	pasd_sas_cntlr_config->usBIOSMinorRevision = 
+				asd->hw_profile.bios_min_ver; 
+	pasd_sas_cntlr_config->usBIOSBuildRevision = 
+				asd->hw_profile.bios_bld_num & 0xffff; 
+	pasd_sas_cntlr_config->usBIOSReleaseRevision = 
+				asd->hw_profile.bios_bld_num >> 16; 
+	
+	pasd_sas_cntlr_config->uControllerFlags = ASD_SAS_CNTLR_SAS_HBA;
+					   //|ASD_SAS_CNTLR_SATA_HBA;//TBD
+	pasd_sas_cntlr_config->usRromMajorRevision = 0;
+	pasd_sas_cntlr_config->usRromMinorRevision = 0;
+	pasd_sas_cntlr_config->usRromBuildRevision = 0;
+	pasd_sas_cntlr_config->usRromReleaseRevision = 0;
+	pasd_sas_cntlr_config->usRromBIOSMajorRevision = 0;
+	pasd_sas_cntlr_config->usRromBIOSMinorRevision = 0;
+	pasd_sas_cntlr_config->usRromBIOSBuildRevision = 0;
+	pasd_sas_cntlr_config->usRromBIOSReleaseRevision = 0;
+
+done:
+	/* return status */	
+	asd_ctl_copy_to_user((void *)arg, &asd_cntlr_conf_buf, 
+			     asd_user_buf_len, retcode);
+	return err;
+}	
+
+/* Adaptec extension IOCTL handler routines */
+static int asd_ctl_sas_get_adpt_cntlr_conf(unsigned long arg)
+{
+	struct ASD_SAS_GET_ADPT_CNTLR_CONFIG_BUFFER asd_adpt_cntlr_conf_buf;
+	struct ASD_SAS_GET_ADPT_CNTLR_CONFIG *pasd_sas_adpt_cntlr_config;
+	struct IOCTL_HEADER *pioctl_header;
+	struct asd_softc *asd;
+	u_long flags;
+	int asd_user_buf_len;
+	int retcode;
+	int err;
+	
+	asd_user_buf_len = sizeof(asd_adpt_cntlr_conf_buf);
+	if ((err = asd_ctl_check_buf_len(arg, asd_user_buf_len))) {
+		return -EINVAL;
+	}
+	
+	if ((err = copy_from_user(&asd_adpt_cntlr_conf_buf, 
+				  (void *)arg, 
+				  asd_user_buf_len))) {
+		return -EFAULT;
+	}
+	
+	pioctl_header = &asd_adpt_cntlr_conf_buf.IoctlHeader;
+	
+	asd = asd_get_softc_by_hba_index(pioctl_header->IOControllerNumber);
+	if (asd == NULL) {
+		/* Requested controller not found */
+		retcode = ASD_SAS_STATUS_INVALID_PARAMETER;
+		err = -ENODEV;
+		goto done;
+	}
+
+	pasd_sas_adpt_cntlr_config = &asd_adpt_cntlr_conf_buf.Configuration;
+
+	asd_lock(asd, &flags);
+	pasd_sas_adpt_cntlr_config->usPCIVendorID = asd_pci_dev(asd)->vendor;
+	pasd_sas_adpt_cntlr_config->usPCIDeviceID = asd_pci_dev(asd)->device;
+	pasd_sas_adpt_cntlr_config->usPCISubsystemVendorID =  
+					asd_pci_dev(asd)->subsystem_vendor;
+	pasd_sas_adpt_cntlr_config->usPCISubsystemID = 
+					asd_pci_dev(asd)->subsystem_device;
+		
+	if (asd->hw_profile.flash_present) {
+		pasd_sas_adpt_cntlr_config->usFlashManufacturerID =
+					asd->hw_profile.flash_manuf_id;
+		pasd_sas_adpt_cntlr_config->usFlashDeviceID = 
+					asd->hw_profile.flash_dev_id;
+		if (asd->hw_profile.flash_wr_prot) {
+			pasd_sas_adpt_cntlr_config->uControllerFlags 
+				= ASD_ADPT_CNTLR_FLASH_READONLY;
+		}
+		retcode = ASD_SAS_STATUS_SUCCESS;
+	} else {
+		pasd_sas_adpt_cntlr_config->usFlashManufacturerID 
+				= ASD_SAS_APDT_INVALID_FLASH_MANUFACTURER_ID; 
+		pasd_sas_adpt_cntlr_config->usFlashDeviceID 
+				= ASD_SAS_ADPT_INVALID_FLASH_DEVICE_ID; 
+		pasd_sas_adpt_cntlr_config->uControllerFlags 
+				= ASD_ADPT_CNTLR_FLASH_NOT_PRESENT; 
+		retcode = ASD_SAS_STATUS_FAILED;
+	}
+	asd_unlock(asd, &flags);
+done:
+	/* return status */	
+	asd_ctl_copy_to_user((void *)arg, &asd_adpt_cntlr_conf_buf, 
+			     asd_user_buf_len, retcode);
+	return err;
+}
+
+static int asd_ctl_sas_get_nv_seg_prop(unsigned long arg)
+{
+	struct ASD_SAS_NV_SEGMENT_PROPERTIES_BUFFER asd_nvseg_prop_buf;
+	struct ASD_SAS_NV_SEGMENT_PROPERTIES *pasd_nvseg_prop;
+	struct IOCTL_HEADER *pioctl_header;
+	struct asd_softc *asd;
+	u_long flags;
+	uint32_t seg_offset, nv_offset;
+	uint32_t pad_size, image_size, attr, bytes_read;
+	int asd_user_buf_len;
+	int err;
+	int retcode; 
+	
+	asd_user_buf_len = sizeof(asd_nvseg_prop_buf);
+	if ((err = asd_ctl_check_buf_len(arg, asd_user_buf_len))) {
+		return -EINVAL;
+	}
+	
+	if ((err = copy_from_user(&asd_nvseg_prop_buf, 
+				  (void *)arg, 
+				  asd_user_buf_len))) {
+		return -EFAULT;
+	}
+	
+	pioctl_header = &asd_nvseg_prop_buf.IoctlHeader;
+	
+	asd = asd_get_softc_by_hba_index(pioctl_header->IOControllerNumber);
+	if (asd == NULL) {
+		/* Requested controller not found */
+		retcode = ASD_SAS_STATUS_INVALID_PARAMETER; 
+		err = -ENODEV;
+		goto done;
+	}
+	
+	err = 0;
+	retcode = ASD_SAS_STATUS_SUCCESS;
+	pasd_nvseg_prop = &asd_nvseg_prop_buf.Information;
+	asd_lock(asd, &flags);
+	
+	switch (pasd_nvseg_prop->uSegmentID) {
+	case ASD_SAS_SEGMENT_ID_MANUFACTURING_SECTOR0:
+	{
+		struct asd_manuf_base_seg_layout manuf_layout;
+		
+		if ((err = asd_hwi_search_nv_segment(asd, NVRAM_MANUF_TYPE,
+				&nv_offset, &pad_size, &image_size, 
+				&attr)) != 0) {
+			err = -1;
+			break;
+		}
+		asd_ctl_map_seg_attr_to_ext(attr, 
+			&pasd_nvseg_prop->usSegmentAttributes); 
+		
+		seg_offset = 0;
+		memset(&manuf_layout, 0x0, sizeof(manuf_layout));
+		
+		/* Read Manufacturing base segment */
+		if (asd_hwi_read_nv_segment(asd, NVRAM_MANUF_TYPE, 
+				&manuf_layout, seg_offset, 
+				sizeof(manuf_layout), &bytes_read) != 0) {
+			err = -1;
+			break;
+		}
+		image_size = manuf_layout.sector_size;
+		pad_size = image_size;
+		break;
+	}
+	case ASD_SAS_SEGMENT_ID_CTRL_A_USER_SETTINGS0:
+	{
+		struct asd_pci_layout pci_layout;
+
+		if ((err = asd_hwi_search_nv_segment(asd, NVRAM_CTRL_A_SETTING,
+				&nv_offset, &pad_size, &image_size, 
+				&attr)) != 0) {
+			err = -1;
+			break;
+		}
+		asd_ctl_map_seg_attr_to_ext(attr, 
+			&pasd_nvseg_prop->usSegmentAttributes); 
+		
+		seg_offset = 0;
+		memset(&pci_layout, 0x0, sizeof(pci_layout));
+		
+		/* Read Ctrl-A first segment */
+		if (asd_hwi_read_nv_segment(asd, NVRAM_CTRL_A_SETTING, 
+				&pci_layout, seg_offset, sizeof(pci_layout),
+				&bytes_read) != 0) {
+			err = -1;
+			break;
+		}
+		image_size = pci_layout.image_size;
+		pad_size = image_size;
+		break;
+	}
+	case ASD_SAS_SEGMENT_ID_FLASH_DIRECTORY0:
+	{
+		struct asd_flash_dir_layout flash_dir;
+		uint32_t nv_addr, active_entries;
+		int i;
+		if (asd_hwi_search_nv_cookie(asd, &nv_addr, &flash_dir) != 0) {
+			err = -1;
+			break;
+		}
+		seg_offset = 0;
+		active_entries = 0;
+		for (i = 0; i < NVRAM_MAX_ENTRIES; i++) {
+			if (flash_dir.ae_mask & (1 << i)) {
+				active_entries++;
+			}
+		}
+		image_size = sizeof(flash_dir) +
+			     (active_entries * 
+			     sizeof(struct asd_fd_entry_layout));
+		pad_size = sizeof(flash_dir) + 
+			   (NVRAM_MAX_ENTRIES * 
+			   sizeof(struct asd_fd_entry_layout));
+		break;
+	}
+	case ASD_SAS_SEGMENT_ID_FLASH0:
+	case ASD_SAS_SEGMENT_ID_SEEPROM0:
+	case ASD_SAS_SEGMENT_ID_COMPATIBILITY_SECTOR0:
+	{
+		pad_size = ASD_SAS_SEGMENT_SIZE_INVALID;
+		image_size = ASD_SAS_SEGMENT_IMAGE_SIZE_INVALID;
+		pasd_nvseg_prop->usSegmentAttributes = 0;
+		break;
+	}
+	default:
+		err = -1;
+		break;
+	}
+	asd_unlock(asd, &flags);
+
+	if (err) {
+		pasd_nvseg_prop->uStatus = ASD_SAS_NV_FAILURE;
+		retcode = ASD_SAS_STATUS_FAILED;
+	} else {
+		pasd_nvseg_prop->uSegmentSize = pad_size;
+		pasd_nvseg_prop->uSegmentImageSize = image_size;
+		pasd_nvseg_prop->uStatus = ASD_SAS_NV_SUCCESS;
+		retcode = ASD_SAS_STATUS_SUCCESS;
+	}
+done:
+	/* return status */	
+	asd_ctl_copy_to_user((void *)arg, &asd_nvseg_prop_buf, 
+			     asd_user_buf_len, retcode);
+	return err;
+}
+
+static int asd_ctl_sas_write_nv_seg(unsigned long arg)
+{
+	struct ASD_SAS_WRITE_NV_SEGMENT_BUFFER *pasd_write_nv_buf;
+	struct ASD_SAS_WRITE_NV_SEGMENT *pasd_write_nv_seg;
+	struct IOCTL_HEADER *pioctl_header;
+	struct asd_ctl_mgmt *pasd_ctl_mgmt;
+	struct asd_softc *asd;
+	uint8_t *psource_buffer;
+	int asd_user_buf_len;
+	int retcode;
+	int err;
+	
+	/* 
+	 * Leave the data buffer at the end of the struct as the
+	 * data buffer will be allocated separately
+	 */
+	asd_user_buf_len = offsetof(struct ASD_SAS_WRITE_NV_SEGMENT_BUFFER, 
+				     bSourceBuffer) ;
+	
+	if ((pasd_write_nv_buf = asd_alloc_mem(asd_user_buf_len,
+					       GFP_ATOMIC)) == NULL) {
+		return -ENOMEM;
+	}
+
+	if ((err = copy_from_user(pasd_write_nv_buf, (void *)arg, 
+				  asd_user_buf_len))) {
+		asd_free_mem(pasd_write_nv_buf);
+		return -EFAULT;
+	}
+	
+	pioctl_header = &pasd_write_nv_buf->IoctlHeader;
+	pasd_write_nv_seg = 
+		&pasd_write_nv_buf->Information;
+
+	if ((err = asd_ctl_check_buf_len(arg, 
+			  asd_user_buf_len
+			  + pasd_write_nv_seg->uBufferLength))) {
+		asd_free_mem(pasd_write_nv_buf);
+		return -EINVAL;
+	}
+	
+	asd = asd_get_softc_by_hba_index(pioctl_header->IOControllerNumber);
+	
+	if (asd == NULL) {
+		/* Requested controller not found */
+		retcode = ASD_SAS_STATUS_INVALID_PARAMETER;
+		err = -ENODEV;
+		goto done;
+	}
+
+	if (!asd->hw_profile.flash_present) {
+		retcode = ASD_SAS_STATUS_FAILED;
+		err = -EINVAL;
+		goto done;
+	}
+	
+	err = 0;
+	retcode = ASD_SAS_STATUS_SUCCESS; 
+	psource_buffer = NULL;	
+	pasd_ctl_mgmt = &asd->asd_ctl_internal.mgmt;
+
+	if ((psource_buffer = (uint8_t *)asd_valloc_mem(
+				pasd_write_nv_seg->uBufferLength)) == NULL) {
+		retcode = ASD_SAS_STATUS_FAILED;
+		err = -ENOMEM;
+		goto done;
+	}
+	memset(psource_buffer, 0, pasd_write_nv_seg->uBufferLength);
+
+	if ((err = copy_from_user(psource_buffer,
+			 (void *)arg + asd_user_buf_len,
+			 pasd_write_nv_seg->uBufferLength))) {
+		asd_vfree_mem(psource_buffer);
+		retcode = ASD_SAS_STATUS_FAILED;
+		err = -EFAULT;
+		goto done;
+	}
+	
+	down_interruptible(&pasd_ctl_mgmt->sem);
+	err = asd_ctl_write_to_nvram(asd, pasd_write_nv_buf, 
+				     psource_buffer);
+	up(&pasd_ctl_mgmt->sem);
+
+	asd_vfree_mem(psource_buffer);
+
+	retcode = err ? ASD_SAS_STATUS_FAILED : ASD_SAS_STATUS_SUCCESS; 
+done:
+	asd_ctl_copy_to_user((void *)arg, pasd_write_nv_buf, 
+			     asd_user_buf_len, retcode);
+	asd_free_mem(pasd_write_nv_buf);
+	return err;
+}
+
+static int asd_ctl_sas_read_nv_seg(unsigned long arg)
+{
+	struct ASD_SAS_READ_NV_SEGMENT_BUFFER *pasd_read_nv_buf;
+	struct ASD_SAS_READ_NV_SEGMENT *pasd_read_nv_seg;
+	struct IOCTL_HEADER *pioctl_header;
+	struct asd_ctl_mgmt *pasd_ctl_mgmt;
+	struct asd_softc *asd;
+	uint8_t *pdest_buffer;
+	int asd_user_buf_len;
+	int retcode;
+	int err;
+	
+	/* 
+	 * Leave the data buffer at the end of the struct as the
+	 * data buffer will be allocated separately
+	 */
+	asd_user_buf_len = offsetof(struct ASD_SAS_READ_NV_SEGMENT_BUFFER, 
+				     bDestinationBuffer) ;
+	
+	if ((pasd_read_nv_buf = asd_alloc_mem(asd_user_buf_len,
+					      GFP_ATOMIC)) == NULL) {
+		return -ENOMEM;
+	}
+
+	if ((err = copy_from_user(pasd_read_nv_buf, (void *)arg, 
+				  asd_user_buf_len)) != 0) {
+		asd_free_mem(pasd_read_nv_buf);
+		return -EFAULT;
+	}
+	
+	pioctl_header = &pasd_read_nv_buf->IoctlHeader;
+	pasd_read_nv_seg = &pasd_read_nv_buf->Information;
+
+	if ((err = asd_ctl_check_buf_len(arg, 
+			  asd_user_buf_len
+			  + pasd_read_nv_seg->uBytesToRead))) {
+		asd_free_mem(pasd_read_nv_buf);
+		return -EINVAL;
+	}
+	
+	asd = asd_get_softc_by_hba_index(pioctl_header->IOControllerNumber);
+	
+	if (asd == NULL) {
+		/* Requested controller not found */
+		retcode = ASD_SAS_STATUS_INVALID_PARAMETER;
+		err = -ENODEV;
+		goto done;
+	}
+	
+	if (!asd->hw_profile.flash_present) {
+		retcode = ASD_SAS_STATUS_FAILED;
+		err = -EINVAL;
+		goto done;
+	}
+	
+	err = 0;
+	retcode = ASD_SAS_STATUS_SUCCESS; 
+	pdest_buffer = NULL;
+	pasd_ctl_mgmt = &asd->asd_ctl_internal.mgmt;
+	
+	if ((pdest_buffer = (uint8_t *)asd_valloc_mem(
+				pasd_read_nv_seg->uBytesToRead)) == NULL) {
+		retcode = ASD_SAS_STATUS_FAILED;
+		err = -ENOMEM;
+		goto done;
+	}
+	memset(pdest_buffer, 0, pasd_read_nv_seg->uBytesToRead);
+	
+	down_interruptible(&pasd_ctl_mgmt->sem);
+	err = asd_ctl_read_from_nvram(asd, pasd_read_nv_buf, 
+				      pdest_buffer);
+	up(&pasd_ctl_mgmt->sem);
+
+	if (err) {
+		retcode = ASD_SAS_STATUS_FAILED; 
+	} else {
+		retcode = ASD_SAS_STATUS_SUCCESS; 
+		if ((err = copy_to_user((void *)arg + asd_user_buf_len,
+					pdest_buffer,
+					pasd_read_nv_seg->uBytesRead))) {
+			retcode = ASD_SAS_STATUS_FAILED; 
+		}
+	}
+
+	asd_vfree_mem(pdest_buffer);
+done:
+	asd_ctl_copy_to_user((void *)arg, pasd_read_nv_buf, 
+			     asd_user_buf_len, retcode);
+	asd_free_mem(pasd_read_nv_buf);
+	return err;
+}
+
+/* helper routines */
+static int asd_ctl_write_to_nvram(struct asd_softc *asd,
+	struct ASD_SAS_WRITE_NV_SEGMENT_BUFFER *pasd_write_nv_buf,
+	uint8_t *psource_buffer)
+{
+	struct ASD_SAS_WRITE_NV_SEGMENT *pasd_write_nv_seg;
+	struct IOCTL_HEADER *pioctl_header;
+	struct asd_ctl_mgmt *pasd_ctl_mgmt;
+	uint32_t nv_segment_id, nv_offset;
+	uint32_t pad_size, image_size, attr;
+	u_long flags;
+	int retcode;
+	int err;
+	
+	pioctl_header = &pasd_write_nv_buf->IoctlHeader;
+	pasd_write_nv_seg = &pasd_write_nv_buf->Information;
+	pasd_ctl_mgmt = &asd->asd_ctl_internal.mgmt;
+	
+	if (test_and_set_bit(ASD_CTL_INTERNAL_BUSY_BIT_NR, 
+			     &pasd_ctl_mgmt->busy)) { 
+		return -EBUSY;
+	}
+	asd_lock(asd, &flags);
+	err = 0;
+	retcode = ASD_SAS_STATUS_SUCCESS;
+	switch (pasd_write_nv_seg->uSegmentID) {
+	case ASD_SAS_SEGMENT_ID_MANUFACTURING_SECTOR0:
+	{
+		asd_ctl_map_nv_segid_from_ext(pasd_write_nv_seg->uSegmentID,
+					      &nv_segment_id);
+		if ((err = asd_hwi_search_nv_segment(asd, nv_segment_id, 
+				&nv_offset, &pad_size, &image_size, 
+				&attr)) != 0) {
+			err = -1;
+			pasd_write_nv_seg->uStatus = ASD_SAS_NV_FAILURE;
+			break;
+		}
+		err = asd_ctl_write_to_flash(asd, psource_buffer, 
+			nv_segment_id,
+			pasd_write_nv_seg->uDestinationOffset, 
+			pasd_write_nv_seg->uBufferLength);
+		break;
+	}
+	case ASD_SAS_SEGMENT_ID_FLASH0:
+	{
+		err = asd_ctl_write_to_flash(asd, psource_buffer, 
+			NVRAM_NO_SEGMENT_ID,
+			pasd_write_nv_seg->uDestinationOffset, 
+			pasd_write_nv_seg->uBufferLength);
+		break;
+	}
+	case ASD_SAS_SEGMENT_ID_SEEPROM0:
+	case ASD_SAS_SEGMENT_ID_FLASH_DIRECTORY0:
+	case ASD_SAS_SEGMENT_ID_CTRL_A_USER_SETTINGS0:
+	case ASD_SAS_SEGMENT_ID_COMPATIBILITY_SECTOR0:
+	default:
+		pasd_write_nv_seg->uStatus = ASD_SAS_NV_FAILURE;
+		err = -EINVAL;
+		break;
+	}
+
+	asd_unlock(asd, &flags);
+
+	/* return */
+	clear_bit(ASD_CTL_INTERNAL_BUSY_BIT_NR, &pasd_ctl_mgmt->busy);
+	return err;
+}
+
+static int asd_ctl_read_from_nvram(struct asd_softc *asd,
+	struct ASD_SAS_READ_NV_SEGMENT_BUFFER *pasd_read_nv_buf,
+	uint8_t *pdest_buffer)
+{
+	struct ASD_SAS_READ_NV_SEGMENT *pasd_read_nv_seg;
+	struct IOCTL_HEADER *pioctl_header;
+	struct asd_ctl_mgmt *pasd_ctl_mgmt;
+	uint32_t nv_segment_id;
+	u_long flags;
+	int retcode;
+	int err;
+	
+	pioctl_header = &pasd_read_nv_buf->IoctlHeader;
+	pasd_read_nv_seg = &pasd_read_nv_buf->Information;
+	pasd_ctl_mgmt = &asd->asd_ctl_internal.mgmt;
+	
+	if (test_and_set_bit(ASD_CTL_INTERNAL_BUSY_BIT_NR, 
+			     &pasd_ctl_mgmt->busy)) { 
+		return -EBUSY;
+	}
+	err = 0;
+	retcode = ASD_SAS_STATUS_SUCCESS;
+	
+	asd_lock(asd, &flags);
+	switch (pasd_read_nv_seg->uSegmentID) {
+	case ASD_SAS_SEGMENT_ID_CTRL_A_USER_SETTINGS0:
+	case ASD_SAS_SEGMENT_ID_MANUFACTURING_SECTOR0:
+	{
+		asd_ctl_map_nv_segid_from_ext(
+			pasd_read_nv_seg->uSegmentID,
+			&nv_segment_id);
+
+		if (asd_hwi_read_nv_segment(asd, 
+				nv_segment_id,
+				(void *)pdest_buffer,
+				pasd_read_nv_seg->uSourceOffset, 
+				pasd_read_nv_seg->uBytesToRead, 
+				&pasd_read_nv_seg->uBytesRead
+				) != 0) {
+			pasd_read_nv_seg->uStatus = ASD_SAS_NV_FAILURE;
+			err = -EINVAL;
+			break;
+		}
+		pasd_read_nv_seg->uStatus = ASD_SAS_NV_SUCCESS;
+		break;
+	}
+	case ASD_SAS_SEGMENT_ID_FLASH_DIRECTORY0:
+	{
+		struct asd_flash_dir_layout flash_dir;
+		uint32_t nv_addr;
+
+		if (asd_hwi_search_nv_cookie(asd, &nv_addr, &flash_dir) != 0) {
+			err = -1;
+			break;
+		}
+		nv_addr += /*NVRAM_FIRST_DIR_ENTRY +*/
+			pasd_read_nv_seg->uSourceOffset;
+
+		if (asd_hwi_read_nv_segment(asd, NVRAM_NO_SEGMENT_ID,
+				(void *)pdest_buffer, nv_addr,
+				pasd_read_nv_seg->uBytesToRead, 
+				&pasd_read_nv_seg->uBytesRead
+				) != 0) {
+			err = -1;
+			break;
+		}
+		break;
+	}	
+	case ASD_SAS_SEGMENT_ID_FLASH0:
+	{
+		if (asd_hwi_read_nv_segment(asd, 
+				NVRAM_NO_SEGMENT_ID,
+				(void *)pdest_buffer,
+				pasd_read_nv_seg->uSourceOffset, 
+				pasd_read_nv_seg->uBytesToRead, 
+				&pasd_read_nv_seg->uBytesRead
+				) != 0) {
+			pasd_read_nv_seg->uStatus = ASD_SAS_NV_FAILURE;
+			err = -EINVAL;
+			break;
+		}
+		pasd_read_nv_seg->uStatus = ASD_SAS_NV_SUCCESS;
+		break;
+	}
+	case ASD_SAS_SEGMENT_ID_SEEPROM0:
+	case ASD_SAS_SEGMENT_ID_COMPATIBILITY_SECTOR0:/*TBD*/
+	default:
+		pasd_read_nv_seg->uStatus = ASD_SAS_NV_FAILURE;
+		err = -EINVAL;
+		break;
+	}
+	asd_unlock(asd, &flags);
+
+	/* return */
+	clear_bit(ASD_CTL_INTERNAL_BUSY_BIT_NR, &pasd_ctl_mgmt->busy);
+	return err;
+}
+
+static uint32_t asd_ctl_write_to_flash(struct asd_softc *asd, 
+			uint8_t *src_img_addr, uint32_t segment_id, 
+			uint32_t dest_nv_offset, uint32_t src_img_size)
+{
+	uint32_t flash_addr;
+
+	flash_addr = 0;
+
+	/* Need to unlock MBAR key register */
+	flash_addr = asd_pcic_read_dword(asd, PCIC_MBAR_KEY);
+	if (flash_addr != 0) {
+		/* currently locked, need to unlock */
+		asd_pcic_write_dword(asd, PCIC_MBAR_KEY, flash_addr);
+	}
+	if (asd_hwi_write_nv_segment(asd, 
+			(void *)src_img_addr, segment_id, 
+			dest_nv_offset, src_img_size) != 0) {
+		return -EINVAL;
+	}
+	return 0;
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-02-17 17:36 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-17 17:36 [ANNOUNCE] Adaptec SAS/SATA device driver [12/27] Luben Tuikov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.