Commit 473c67f9 authored by Matthew Wilcox's avatar Matthew Wilcox Committed by James Bottomley

[PATCH] sym2 version 2.2.0

Docs
 - The sym53c8xx= kernel parameter no longer exists
 - Correct a typo

Bugfixes
 - The driver really isn't capable of dealing with 64-bit bus addresses
   yet, so bail out early
 - Get rid of SYM_SCAN_TARGETS_HILO (which had no effect) and set the
   shost->reverse_ordering flag instead
 - Associate a scsi_device with the target in slave_alloc instead of
   slave_configure

Printk cleanups
 - Use dev_warn/dev_info where possible
 - Delete PRINT_ADDR, PRINT_TARGET and PRINT_LUN
 - Remove sym_print_target() and sym_print_lun()
 - Make sym_print_addr() call dev_info

Memory allocation related
 - Delete non-dma allocators; use kmalloc/kcalloc directly instead
 - Move memory allocation wrappers from sym_glue to sym_malloc
 - Get rid of m_addr_t; use void * or dma_addr_t as appropriate
 - Change m_pool_ident_t from a struct pci_dev * to a struct device *
 - Use dma_alloc_coherent() instead of pci_alloc_consistent()

Negotiation related
 - Move scsi_transport_spi.h include from sym_glue.c to sym_glue.h
 - Store the current transfer contract settings in the starget attributes
 - Delete sym2_get_offset(), sym2_get_period(), sym2_get_width(),
   sym2_get_dt(), sym2_get_iu() and sym2_get_qas()
 - Use spi_support_wide() (and friends) instead of scsi_device_wide()
 - We don't need tinfo.prev -- we can tell if the contract changed
 - Delete SYM_OPT_ANNOUNCE_TRANSFER_RATE
 - Use spi_display_xfer_agreement()
 - Use sdev->scsi_level instead of the never-set tinfo.curr.scsi_version
 - Instead of checking current xfer settings against our goal, use a
   check_nego flag.
 - Get rid of sym_tinfo and use sym_trans directly.
 - Split the sym_trans options into flags
 - Change width from an u8 into a flag
 - Delete sym_misc.c
 - Remove sym_xpt_async_nego_wide

Linuxisation
 - Use udelay() directly instead of indirecting through UDELAY and sym_udelay
 - Rename some scsi_cmnd pointers from ccb or csio to cmd
 - Use simple_strtoul() instead of a handwritten parser
 - SKIP_SPACES was always being used with 1 as a parameter, and was implicitly
   modifying ptr and len.
 - GET_INT_ARG was doing the same with ptr and len.
 - Use pci_iomap(), pci_iounmap(), ioread8() et al
 - Delete the sym_data_dmamap_*() macros
 - Replace SYM_CONF_IOMAPPED with CONFIG_SCSI_SYM53C8XX_IOMAPPED
 - Delete unused SYM_HAVE_SCCB, SYM_HAVE_M_SVTOB, SYM_HAVE_M_SPOOL

Misc cleanup
 - Move sym_conf.h into sym53c8xx.h
 - Eliminate the unused SYM_SETUP_MAX_LUN, SYM_SCMD_PTR
 - SYM_SETUP_PCI_PARITY and SYM_SETUP_SCSI_PARITY are always defined; simplify
 - Rename sym_pci_chip to sym_chip
 - Write sym_get_hcb() to hide nasty macro abuse
 - sym_lp() doesn't need to take the sym_hcb as an argument
 - sym_get_ccb() works better if you give it the cmd instead of the id/lun
 - We don't use cmd->host_scribble, host->dma_channel, host->n_io_port,
   host->io_port, host->base or host->irq; stop initialising them.
 - sym_tune_dev_queuing() works better if you give it the tcb rather than
   the hcb and target
 - Get rid of sym_driver_name(), just use SYM_DRIVER_NAME directly
 - OUTB/INB/etc macros implicitly use the hcb pointer; pass it explictly instead
 - Map the BARs early instead of mapping and unmapping them as necessary
 - Automatically fall back to ioport accesses if iomem isn't available
 - Get rid of tcb_p, lcb_p and ccb_p typedefs
 - Delete support for big endian chips -- 8xx chips can't be in BE mode
 - Inline sym_slot into sym_device
 - Inline sym_printb_hex() into sym_printl_hex()
 - Don't cast function return values to void
 - Introduce sym_nvram_type()
 - Pass the hcb and starget to sym_check_goals since we already have them
   in the caller
 - Some 0/NULL cleanup
 - Embed the sense buffer in the CCB so it doesn't need to be allocated
   separately
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent cee9a2d6
...@@ -1345,9 +1345,6 @@ running once the system is up. ...@@ -1345,9 +1345,6 @@ running once the system is up.
sym53c416= [HW,SCSI] sym53c416= [HW,SCSI]
See header of drivers/scsi/sym53c416.c. See header of drivers/scsi/sym53c416.c.
sym53c8xx= [HW,SCSI]
See Documentation/scsi/ncr53c8xx.txt.
t128= [HW,SCSI] t128= [HW,SCSI]
See header of drivers/scsi/t128.c. See header of drivers/scsi/t128.c.
......
...@@ -440,7 +440,7 @@ lilo: linux root=/dev/sda2 sym53c8xx.cmd_per_lun=4 sym53c8xx.sync=10 sym53c8xx.d ...@@ -440,7 +440,7 @@ lilo: linux root=/dev/sda2 sym53c8xx.cmd_per_lun=4 sym53c8xx.sync=10 sym53c8xx.d
The following command will install the driver module with the same The following command will install the driver module with the same
options as above. options as above.
modprobe sym53c8xx cmd_per_lun=4 sync=10 debug=0x200" modprobe sym53c8xx cmd_per_lun=4 sync=10 debug=0x200
10.2 Available arguments 10.2 Available arguments
......
# Makefile for the NCR/SYMBIOS/LSI 53C8XX PCI SCSI controllers driver. # Makefile for the NCR/SYMBIOS/LSI 53C8XX PCI SCSI controllers driver.
sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_misc.o sym_nvram.o sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_nvram.o
obj-$(CONFIG_SCSI_SYM53C8XX_2) := sym53c8xx.o obj-$(CONFIG_SCSI_SYM53C8XX_2) := sym53c8xx.o
...@@ -42,10 +42,6 @@ ...@@ -42,10 +42,6 @@
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_SCSI_SYM53C8XX_IOMAPPED
#define SYM_CONF_IOMAPPED
#endif
/* /*
* DMA addressing mode. * DMA addressing mode.
* *
...@@ -144,10 +140,6 @@ struct sym_driver_setup { ...@@ -144,10 +140,6 @@ struct sym_driver_setup {
#define SYM_SETUP_HOST_ID sym_driver_setup.host_id #define SYM_SETUP_HOST_ID sym_driver_setup.host_id
#define boot_verbose sym_driver_setup.verbose #define boot_verbose sym_driver_setup.verbose
/* Always enable parity. */
#define SYM_SETUP_PCI_PARITY 1
#define SYM_SETUP_SCSI_PARITY 1
/* /*
* Initial setup. * Initial setup.
* *
...@@ -170,4 +162,56 @@ extern struct sym_driver_setup sym_driver_setup; ...@@ -170,4 +162,56 @@ extern struct sym_driver_setup sym_driver_setup;
extern unsigned int sym_debug_flags; extern unsigned int sym_debug_flags;
#define DEBUG_FLAGS sym_debug_flags #define DEBUG_FLAGS sym_debug_flags
/*
* Max number of targets.
* Maximum is 16 and you are advised not to change this value.
*/
#ifndef SYM_CONF_MAX_TARGET
#define SYM_CONF_MAX_TARGET (16)
#endif
/*
* Max number of logical units.
* SPI-2 allows up to 64 logical units, but in real life, target
* that implements more that 7 logical units are pretty rare.
* Anyway, the cost of accepting up to 64 logical unit is low in
* this driver, thus going with the maximum is acceptable.
*/
#ifndef SYM_CONF_MAX_LUN
#define SYM_CONF_MAX_LUN (64)
#endif
/*
* Max number of IO control blocks queued to the controller.
* Each entry needs 8 bytes and the queues are allocated contiguously.
* Since we donnot want to allocate more than a page, the theorical
* maximum is PAGE_SIZE/8. For safety, we announce a bit less to the
* access method. :)
* When not supplied, as it is suggested, the driver compute some
* good value for this parameter.
*/
/* #define SYM_CONF_MAX_START (PAGE_SIZE/8 - 16) */
/*
* Support for Immediate Arbitration.
* Not advised.
*/
/* #define SYM_CONF_IARB_SUPPORT */
/*
* Only relevant if IARB support configured.
* - Max number of successive settings of IARB hints.
* - Set IARB on arbitration lost.
*/
#define SYM_CONF_IARB_MAX 3
#define SYM_CONF_SET_IARB_ON_ARB_LOST 1
/*
* Returning wrong residuals may make problems.
* When zero, this define tells the driver to
* always return 0 as transfer residual.
* Btw, all my testings of residuals have succeeded.
*/
#define SYM_SETUP_RESIDUAL_SUPPORT 1
#endif /* SYM53C8XX_H */ #endif /* SYM53C8XX_H */
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef SYM_CONF_H
#define SYM_CONF_H
#include "sym53c8xx.h"
/*
* Max number of targets.
* Maximum is 16 and you are advised not to change this value.
*/
#ifndef SYM_CONF_MAX_TARGET
#define SYM_CONF_MAX_TARGET (16)
#endif
/*
* Max number of logical units.
* SPI-2 allows up to 64 logical units, but in real life, target
* that implements more that 7 logical units are pretty rare.
* Anyway, the cost of accepting up to 64 logical unit is low in
* this driver, thus going with the maximum is acceptable.
*/
#ifndef SYM_CONF_MAX_LUN
#define SYM_CONF_MAX_LUN (64)
#endif
/*
* Max number of IO control blocks queued to the controller.
* Each entry needs 8 bytes and the queues are allocated contiguously.
* Since we donnot want to allocate more than a page, the theorical
* maximum is PAGE_SIZE/8. For safety, we announce a bit less to the
* access method. :)
* When not supplied, as it is suggested, the driver compute some
* good value for this parameter.
*/
/* #define SYM_CONF_MAX_START (PAGE_SIZE/8 - 16) */
/*
* Support for Immediate Arbitration.
* Not advised.
*/
/* #define SYM_CONF_IARB_SUPPORT */
/*
* Only relevant if IARB support configured.
* - Max number of successive settings of IARB hints.
* - Set IARB on arbitration lost.
*/
#define SYM_CONF_IARB_MAX 3
#define SYM_CONF_SET_IARB_ON_ARB_LOST 1
/*
* Returning wrong residuals may make problems.
* When zero, this define tells the driver to
* always return 0 as transfer residual.
* Btw, all my testings of residuals have succeeded.
*/
#define SYM_SETUP_RESIDUAL_SUPPORT 1
/*
* Supported maximum number of LUNs to announce to
* the access method.
* The driver supports up to 64 LUNs per target as
* required by SPI-2/SPI-3. However some SCSI devices
* designed prior to these specifications or not being
* conformant may be highly confused when they are
* asked about a LUN > 7.
*/
#ifndef SYM_SETUP_MAX_LUN
#define SYM_SETUP_MAX_LUN (8)
#endif
#endif /* SYM_CONF_H */
...@@ -40,13 +40,13 @@ ...@@ -40,13 +40,13 @@
#ifndef SYM_DEFS_H #ifndef SYM_DEFS_H
#define SYM_DEFS_H #define SYM_DEFS_H
#define SYM_VERSION "2.1.18n" #define SYM_VERSION "2.2.0"
#define SYM_DRIVER_NAME "sym-" SYM_VERSION #define SYM_DRIVER_NAME "sym-" SYM_VERSION
/* /*
* SYM53C8XX device features descriptor. * SYM53C8XX device features descriptor.
*/ */
struct sym_pci_chip { struct sym_chip {
u_short device_id; u_short device_id;
u_short revision_id; u_short revision_id;
char *name; char *name;
......
...@@ -361,7 +361,7 @@ static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based"); ...@@ -361,7 +361,7 @@ static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
* Find the most appropriate firmware for a chip. * Find the most appropriate firmware for a chip.
*/ */
struct sym_fw * struct sym_fw *
sym_find_firmware(struct sym_pci_chip *chip) sym_find_firmware(struct sym_chip *chip)
{ {
if (chip->features & FE_LDSTR) if (chip->features & FE_LDSTR)
return &sym_fw2; return &sym_fw2;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -66,7 +66,7 @@ static void *___sym_malloc(m_pool_p mp, int size) ...@@ -66,7 +66,7 @@ static void *___sym_malloc(m_pool_p mp, int size)
int i = 0; int i = 0;
int s = (1 << SYM_MEM_SHIFT); int s = (1 << SYM_MEM_SHIFT);
int j; int j;
m_addr_t a; void *a;
m_link_p h = mp->h; m_link_p h = mp->h;
if (size > SYM_MEM_CLUSTER_SIZE) if (size > SYM_MEM_CLUSTER_SIZE)
...@@ -88,7 +88,7 @@ static void *___sym_malloc(m_pool_p mp, int size) ...@@ -88,7 +88,7 @@ static void *___sym_malloc(m_pool_p mp, int size)
++j; ++j;
s <<= 1; s <<= 1;
} }
a = (m_addr_t) h[j].next; a = h[j].next;
if (a) { if (a) {
h[j].next = h[j].next->next; h[j].next = h[j].next->next;
while (j > i) { while (j > i) {
...@@ -101,7 +101,7 @@ static void *___sym_malloc(m_pool_p mp, int size) ...@@ -101,7 +101,7 @@ static void *___sym_malloc(m_pool_p mp, int size)
#ifdef DEBUG #ifdef DEBUG
printf("___sym_malloc(%d) = %p\n", size, (void *) a); printf("___sym_malloc(%d) = %p\n", size, (void *) a);
#endif #endif
return (void *) a; return a;
} }
/* /*
...@@ -112,7 +112,7 @@ static void ___sym_mfree(m_pool_p mp, void *ptr, int size) ...@@ -112,7 +112,7 @@ static void ___sym_mfree(m_pool_p mp, void *ptr, int size)
int i = 0; int i = 0;
int s = (1 << SYM_MEM_SHIFT); int s = (1 << SYM_MEM_SHIFT);
m_link_p q; m_link_p q;
m_addr_t a, b; unsigned long a, b;
m_link_p h = mp->h; m_link_p h = mp->h;
#ifdef DEBUG #ifdef DEBUG
...@@ -127,12 +127,12 @@ static void ___sym_mfree(m_pool_p mp, void *ptr, int size) ...@@ -127,12 +127,12 @@ static void ___sym_mfree(m_pool_p mp, void *ptr, int size)
++i; ++i;
} }
a = (m_addr_t) ptr; a = (unsigned long)ptr;
while (1) { while (1) {
if (s == SYM_MEM_CLUSTER_SIZE) { if (s == SYM_MEM_CLUSTER_SIZE) {
#ifdef SYM_MEM_FREE_UNUSED #ifdef SYM_MEM_FREE_UNUSED
M_FREE_MEM_CLUSTER(a); M_FREE_MEM_CLUSTER((void *)a);
#else #else
((m_link_p) a)->next = h[i].next; ((m_link_p) a)->next = h[i].next;
h[i].next = (m_link_p) a; h[i].next = (m_link_p) a;
...@@ -194,58 +194,40 @@ static void __sym_mfree(m_pool_p mp, void *ptr, int size, char *name) ...@@ -194,58 +194,40 @@ static void __sym_mfree(m_pool_p mp, void *ptr, int size, char *name)
* With DMA abstraction, we use functions (methods), to * With DMA abstraction, we use functions (methods), to
* distinguish between non DMAable memory and DMAable memory. * distinguish between non DMAable memory and DMAable memory.
*/ */
static m_addr_t ___mp0_get_mem_cluster(m_pool_p mp) static void *___mp0_get_mem_cluster(m_pool_p mp)
{ {
m_addr_t m = (m_addr_t) sym_get_mem_cluster(); void *m = sym_get_mem_cluster();
if (m) if (m)
++mp->nump; ++mp->nump;
return m; return m;
} }
#ifdef SYM_MEM_FREE_UNUSED #ifdef SYM_MEM_FREE_UNUSED
static void ___mp0_free_mem_cluster(m_pool_p mp, m_addr_t m) static void ___mp0_free_mem_cluster(m_pool_p mp, void *m)
{ {
sym_free_mem_cluster(m); sym_free_mem_cluster(m);
--mp->nump; --mp->nump;
} }
#endif
#ifdef SYM_MEM_FREE_UNUSED
static struct sym_m_pool mp0 =
{NULL, ___mp0_get_mem_cluster, ___mp0_free_mem_cluster};
#else #else
static struct sym_m_pool mp0 = #define ___mp0_free_mem_cluster NULL
{NULL, ___mp0_get_mem_cluster};
#endif #endif
/* static struct sym_m_pool mp0 = {
* Actual memory allocation routine for non-DMAed memory. NULL,
*/ ___mp0_get_mem_cluster,
void *sym_calloc_unlocked(int size, char *name) ___mp0_free_mem_cluster
{ };
void *m;
m = __sym_calloc(&mp0, size, name);
return m;
}
/*
* Its counter-part.
*/
void sym_mfree_unlocked(void *ptr, int size, char *name)
{
__sym_mfree(&mp0, ptr, size, name);
}
/* /*
* Methods that maintains DMAable pools according to user allocations. * Methods that maintains DMAable pools according to user allocations.
* New pools are created on the fly when a new pool id is provided. * New pools are created on the fly when a new pool id is provided.
* They are deleted on the fly when they get emptied. * They are deleted on the fly when they get emptied.
*/ */
/* Get a memory cluster that matches the DMA contraints of a given pool */ /* Get a memory cluster that matches the DMA constraints of a given pool */
static m_addr_t ___get_dma_mem_cluster(m_pool_p mp) static void * ___get_dma_mem_cluster(m_pool_p mp)
{ {
m_vtob_p vbp; m_vtob_p vbp;
m_addr_t vaddr; void *vaddr;
vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB"); vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB");
if (!vbp) if (!vbp)
...@@ -257,16 +239,15 @@ static m_addr_t ___get_dma_mem_cluster(m_pool_p mp) ...@@ -257,16 +239,15 @@ static m_addr_t ___get_dma_mem_cluster(m_pool_p mp)
vbp->next = mp->vtob[hc]; vbp->next = mp->vtob[hc];
mp->vtob[hc] = vbp; mp->vtob[hc] = vbp;
++mp->nump; ++mp->nump;
return (m_addr_t) vaddr;
} }
return vaddr; return vaddr;
out_err: out_err:
return 0; return NULL;
} }
#ifdef SYM_MEM_FREE_UNUSED #ifdef SYM_MEM_FREE_UNUSED
/* Free a memory cluster and associated resources for DMA */ /* Free a memory cluster and associated resources for DMA */
static void ___free_dma_mem_cluster(m_pool_p mp, m_addr_t m) static void ___free_dma_mem_cluster(m_pool_p mp, void *m)
{ {
m_vtob_p *vbpp, vbp; m_vtob_p *vbpp, vbp;
int hc = VTOB_HASH_CODE(m); int hc = VTOB_HASH_CODE(m);
...@@ -297,23 +278,17 @@ static __inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat) ...@@ -297,23 +278,17 @@ static __inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat)
/* Create a new memory DMAable pool (when fetch failed) */ /* Create a new memory DMAable pool (when fetch failed) */
static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat) static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat)
{ {
m_pool_p mp = NULL; m_pool_p mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
if (mp) { if (mp) {
mp->dev_dmat = dev_dmat; mp->dev_dmat = dev_dmat;
if (!sym_m_create_dma_mem_tag(mp)) { mp->get_mem_cluster = ___get_dma_mem_cluster;
mp->get_mem_cluster = ___get_dma_mem_cluster;
#ifdef SYM_MEM_FREE_UNUSED #ifdef SYM_MEM_FREE_UNUSED
mp->free_mem_cluster = ___free_dma_mem_cluster; mp->free_mem_cluster = ___free_dma_mem_cluster;
#endif #endif
mp->next = mp0.next; mp->next = mp0.next;
mp0.next = mp; mp0.next = mp;
return mp; return mp;
}
} }
if (mp)
__sym_mfree(&mp0, mp, sizeof(*mp), "MPOOL");
return NULL; return NULL;
} }
...@@ -327,68 +302,81 @@ static void ___del_dma_pool(m_pool_p p) ...@@ -327,68 +302,81 @@ static void ___del_dma_pool(m_pool_p p)
pp = &(*pp)->next; pp = &(*pp)->next;
if (*pp) { if (*pp) {
*pp = (*pp)->next; *pp = (*pp)->next;
sym_m_delete_dma_mem_tag(p);
__sym_mfree(&mp0, p, sizeof(*p), "MPOOL"); __sym_mfree(&mp0, p, sizeof(*p), "MPOOL");
} }
} }
#endif #endif
/* This lock protects only the memory allocation/free. */
static DEFINE_SPINLOCK(sym53c8xx_lock);
/* /*
* Actual allocator for DMAable memory. * Actual allocator for DMAable memory.
*/ */
void *__sym_calloc_dma_unlocked(m_pool_ident_t dev_dmat, int size, char *name) void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name)
{ {
unsigned long flags;
m_pool_p mp; m_pool_p mp;
void *m = NULL; void *m = NULL;
spin_lock_irqsave(&sym53c8xx_lock, flags);
mp = ___get_dma_pool(dev_dmat); mp = ___get_dma_pool(dev_dmat);
if (!mp) if (!mp)
mp = ___cre_dma_pool(dev_dmat); mp = ___cre_dma_pool(dev_dmat);
if (mp) if (!mp)
m = __sym_calloc(mp, size, name); goto out;
m = __sym_calloc(mp, size, name);
#ifdef SYM_MEM_FREE_UNUSED #ifdef SYM_MEM_FREE_UNUSED
if (mp && !mp->nump) if (!mp->nump)
___del_dma_pool(mp); ___del_dma_pool(mp);
#endif #endif
out:
spin_unlock_irqrestore(&sym53c8xx_lock, flags);
return m; return m;
} }
/* void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name)
* Its counter-part.
*/
void
__sym_mfree_dma_unlocked(m_pool_ident_t dev_dmat, void *m, int size, char *name)
{ {
unsigned long flags;
m_pool_p mp; m_pool_p mp;
spin_lock_irqsave(&sym53c8xx_lock, flags);
mp = ___get_dma_pool(dev_dmat); mp = ___get_dma_pool(dev_dmat);
if (mp) if (!mp)
__sym_mfree(mp, m, size, name); goto out;
__sym_mfree(mp, m, size, name);
#ifdef SYM_MEM_FREE_UNUSED #ifdef SYM_MEM_FREE_UNUSED
if (mp && !mp->nump) if (!mp->nump)
___del_dma_pool(mp); ___del_dma_pool(mp);
#endif #endif
out:
spin_unlock_irqrestore(&sym53c8xx_lock, flags);
} }
/* /*
* Actual virtual to bus physical address translator * Actual virtual to bus physical address translator
* for 32 bit addressable DMAable memory. * for 32 bit addressable DMAable memory.
*/ */
u32 __vtobus_unlocked(m_pool_ident_t dev_dmat, void *m) dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m)
{ {
unsigned long flags;
m_pool_p mp; m_pool_p mp;
int hc = VTOB_HASH_CODE(m); int hc = VTOB_HASH_CODE(m);
m_vtob_p vp = NULL; m_vtob_p vp = NULL;
m_addr_t a = ((m_addr_t) m) & ~SYM_MEM_CLUSTER_MASK; void *a = (void *)((unsigned long)m & ~SYM_MEM_CLUSTER_MASK);
dma_addr_t b;
spin_lock_irqsave(&sym53c8xx_lock, flags);
mp = ___get_dma_pool(dev_dmat); mp = ___get_dma_pool(dev_dmat);
if (mp) { if (mp) {
vp = mp->vtob[hc]; vp = mp->vtob[hc];
while (vp && (m_addr_t) vp->vaddr != a) while (vp && vp->vaddr != a)
vp = vp->next; vp = vp->next;
} }
if (!vp) if (!vp)
panic("sym: VTOBUS FAILED!\n"); panic("sym: VTOBUS FAILED!\n");
return (u32)(vp ? vp->baddr + (((m_addr_t) m) - a) : 0); b = vp->baddr + (m - a);
spin_unlock_irqrestore(&sym53c8xx_lock, flags);
return b;
} }
/*
* Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family
* of PCI-SCSI IO processors.
*
* Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr>
*
* This driver is derived from the Linux sym53c8xx driver.
* Copyright (C) 1998-2000 Gerard Roudier
*
* The sym53c8xx driver is derived from the ncr53c8xx driver that had been
* a port of the FreeBSD ncr driver to Linux-1.2.13.
*
* The original ncr driver has been written for 386bsd and FreeBSD by
* Wolfgang Stanglmeier <wolf@cologne.de>
* Stefan Esser <se@mi.Uni-Koeln.de>
* Copyright (C) 1994 Wolfgang Stanglmeier
*
* Other major contributions:
*
* NVRAM detection and reading.
* Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
*
*-----------------------------------------------------------------------------
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "sym_glue.h"
#ifdef SYM_OPT_ANNOUNCE_TRANSFER_RATE
/*
* Announce transfer rate if anything changed since last announcement.
*/
void sym_announce_transfer_rate(struct sym_hcb *np, int target)
{
tcb_p tp = &np->target[target];
#define __tprev tp->tinfo.prev
#define __tcurr tp->tinfo.curr
if (__tprev.options == __tcurr.options &&
__tprev.width == __tcurr.width &&
__tprev.offset == __tcurr.offset &&
!(__tprev.offset && __tprev.period != __tcurr.period))
return;
__tprev.options = __tcurr.options;
__tprev.width = __tcurr.width;
__tprev.offset = __tcurr.offset;
__tprev.period = __tcurr.period;
if (__tcurr.offset && __tcurr.period) {
u_int period, f10, mb10;
char *scsi;
period = f10 = mb10 = 0;
scsi = "FAST-5";
if (__tcurr.period <= 9) {
scsi = "FAST-80";
period = 125;
mb10 = 1600;
}
else {
if (__tcurr.period <= 11) {
scsi = "FAST-40";
period = 250;
if (__tcurr.period == 11)
period = 303;
}
else if (__tcurr.period < 25) {
scsi = "FAST-20";
if (__tcurr.period == 12)
period = 500;
}
else if (__tcurr.period <= 50) {
scsi = "FAST-10";
}
if (!period)
period = 40 * __tcurr.period;
f10 = 100000 << (__tcurr.width ? 1 : 0);
mb10 = (f10 + period/2) / period;
}
printf_info (
"%s:%d: %s %sSCSI %d.%d MB/s %s%s%s (%d.%d ns, offset %d)\n",
sym_name(np), target, scsi, __tcurr.width? "WIDE " : "",
mb10/10, mb10%10,
(__tcurr.options & PPR_OPT_DT) ? "DT" : "ST",
(__tcurr.options & PPR_OPT_IU) ? " IU" : "",
(__tcurr.options & PPR_OPT_QAS) ? " QAS" : "",
period/10, period%10, __tcurr.offset);
}
else
printf_info ("%s:%d: %sasynchronous.\n",
sym_name(np), target, __tcurr.width? "wide " : "");
}
#undef __tprev
#undef __tcurr
#endif /* SYM_OPT_ANNOUNCE_TRANSFER_RATE */
...@@ -47,7 +47,7 @@ static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120}; ...@@ -47,7 +47,7 @@ static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
/* /*
* Get host setup from NVRAM. * Get host setup from NVRAM.
*/ */
void sym_nvram_setup_host(struct sym_hcb *np, struct sym_nvram *nvram) void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
{ {
/* /*
* Get parity checking, host ID, verbose mode * Get parity checking, host ID, verbose mode
...@@ -61,7 +61,7 @@ void sym_nvram_setup_host(struct sym_hcb *np, struct sym_nvram *nvram) ...@@ -61,7 +61,7 @@ void sym_nvram_setup_host(struct sym_hcb *np, struct sym_nvram *nvram)
if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
np->verbose += 1; np->verbose += 1;
if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO) if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
np->usrflags |= SYM_SCAN_TARGETS_HILO; shost->reverse_ordering = 1;
if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET) if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
np->usrflags |= SYM_AVOID_BUS_RESET; np->usrflags |= SYM_AVOID_BUS_RESET;
break; break;
...@@ -253,7 +253,7 @@ static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) ...@@ -253,7 +253,7 @@ static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram)
static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg, static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg,
int bit_mode) int bit_mode)
{ {
UDELAY (5); udelay(5);
switch (bit_mode) { switch (bit_mode) {
case SET_BIT: case SET_BIT:
*gpreg |= write_bit; *gpreg |= write_bit;
...@@ -269,8 +269,8 @@ static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpre ...@@ -269,8 +269,8 @@ static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpre
break; break;
} }
OUTB (nc_gpreg, *gpreg); OUTB(np, nc_gpreg, *gpreg);
UDELAY (5); udelay(5);
} }
/* /*
...@@ -303,7 +303,7 @@ static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_ ...@@ -303,7 +303,7 @@ static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_
S24C16_set_bit(np, write_bit, gpreg, SET_BIT); S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
S24C16_set_bit(np, 0, gpreg, SET_CLK); S24C16_set_bit(np, 0, gpreg, SET_CLK);
if (read_bit) if (read_bit)
*read_bit = INB (nc_gpreg); *read_bit = INB(np, nc_gpreg);
S24C16_set_bit(np, 0, gpreg, CLR_CLK); S24C16_set_bit(np, 0, gpreg, CLR_CLK);
S24C16_set_bit(np, 0, gpreg, CLR_BIT); S24C16_set_bit(np, 0, gpreg, CLR_BIT);
} }
...@@ -315,9 +315,9 @@ static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_ ...@@ -315,9 +315,9 @@ static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_
static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg, static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg,
u_char *gpcntl) u_char *gpcntl)
{ {
OUTB (nc_gpcntl, *gpcntl & 0xfe); OUTB(np, nc_gpcntl, *gpcntl & 0xfe);
S24C16_do_bit(np, NULL, write_bit, gpreg); S24C16_do_bit(np, NULL, write_bit, gpreg);
OUTB (nc_gpcntl, *gpcntl); OUTB(np, nc_gpcntl, *gpcntl);
} }
/* /*
...@@ -327,9 +327,9 @@ static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gp ...@@ -327,9 +327,9 @@ static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gp
static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg, static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg,
u_char *gpcntl) u_char *gpcntl)
{ {
OUTB (nc_gpcntl, *gpcntl | 0x01); OUTB(np, nc_gpcntl, *gpcntl | 0x01);
S24C16_do_bit(np, read_bit, 1, gpreg); S24C16_do_bit(np, read_bit, 1, gpreg);
OUTB (nc_gpcntl, *gpcntl); OUTB(np, nc_gpcntl, *gpcntl);
} }
/* /*
...@@ -379,13 +379,13 @@ static int sym_write_S24C16_nvram(struct sym_device *np, int offset, ...@@ -379,13 +379,13 @@ static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
int x; int x;
/* save current state of GPCNTL and GPREG */ /* save current state of GPCNTL and GPREG */
old_gpreg = INB (nc_gpreg); old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB (nc_gpcntl); old_gpcntl = INB(np, nc_gpcntl);
gpcntl = old_gpcntl & 0x1c; gpcntl = old_gpcntl & 0x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB (nc_gpreg, old_gpreg); OUTB(np, nc_gpreg, old_gpreg);
OUTB (nc_gpcntl, gpcntl); OUTB(np, nc_gpcntl, gpcntl);
/* this is to set NVRAM into a known state with GPIO0/1 both low */ /* this is to set NVRAM into a known state with GPIO0/1 both low */
gpreg = old_gpreg; gpreg = old_gpreg;
...@@ -414,8 +414,8 @@ static int sym_write_S24C16_nvram(struct sym_device *np, int offset, ...@@ -414,8 +414,8 @@ static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
} }
/* return GPIO0/1 to original states after having accessed NVRAM */ /* return GPIO0/1 to original states after having accessed NVRAM */
OUTB (nc_gpcntl, old_gpcntl); OUTB(np, nc_gpcntl, old_gpcntl);
OUTB (nc_gpreg, old_gpreg); OUTB(np, nc_gpreg, old_gpreg);
return 0; return 0;
} }
...@@ -433,13 +433,13 @@ static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data ...@@ -433,13 +433,13 @@ static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data
int x; int x;
/* save current state of GPCNTL and GPREG */ /* save current state of GPCNTL and GPREG */
old_gpreg = INB (nc_gpreg); old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB (nc_gpcntl); old_gpcntl = INB(np, nc_gpcntl);
gpcntl = old_gpcntl & 0x1c; gpcntl = old_gpcntl & 0x1c;
/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
OUTB (nc_gpreg, old_gpreg); OUTB(np, nc_gpreg, old_gpreg);
OUTB (nc_gpcntl, gpcntl); OUTB(np, nc_gpcntl, gpcntl);
/* this is to set NVRAM into a known state with GPIO0/1 both low */ /* this is to set NVRAM into a known state with GPIO0/1 both low */
gpreg = old_gpreg; gpreg = old_gpreg;
...@@ -475,7 +475,7 @@ static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data ...@@ -475,7 +475,7 @@ static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data
/* now set up GPIO0 for inputting data */ /* now set up GPIO0 for inputting data */
gpcntl |= 0x01; gpcntl |= 0x01;
OUTB (nc_gpcntl, gpcntl); OUTB(np, nc_gpcntl, gpcntl);
/* input all requested data - only part of total NVRAM */ /* input all requested data - only part of total NVRAM */
for (x = 0; x < len; x++) for (x = 0; x < len; x++)
...@@ -483,13 +483,13 @@ static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data ...@@ -483,13 +483,13 @@ static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data
/* finally put NVRAM back in inactive mode */ /* finally put NVRAM back in inactive mode */
gpcntl &= 0xfe; gpcntl &= 0xfe;
OUTB (nc_gpcntl, gpcntl); OUTB(np, nc_gpcntl, gpcntl);
S24C16_stop(np, &gpreg); S24C16_stop(np, &gpreg);
retv = 0; retv = 0;
out: out:
/* return GPIO0/1 to original states after having accessed NVRAM */ /* return GPIO0/1 to original states after having accessed NVRAM */
OUTB (nc_gpcntl, old_gpcntl); OUTB(np, nc_gpcntl, old_gpcntl);
OUTB (nc_gpreg, old_gpreg); OUTB(np, nc_gpreg, old_gpreg);
return retv; return retv;
} }
...@@ -546,9 +546,9 @@ static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) ...@@ -546,9 +546,9 @@ static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
*/ */
static void T93C46_Clk(struct sym_device *np, u_char *gpreg) static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
{ {
OUTB (nc_gpreg, *gpreg | 0x04); OUTB(np, nc_gpreg, *gpreg | 0x04);
UDELAY (2); udelay(2);
OUTB (nc_gpreg, *gpreg); OUTB(np, nc_gpreg, *gpreg);
} }
/* /*
...@@ -556,9 +556,9 @@ static void T93C46_Clk(struct sym_device *np, u_char *gpreg) ...@@ -556,9 +556,9 @@ static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
*/ */
static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg) static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg)
{ {
UDELAY (2); udelay(2);
T93C46_Clk(np, gpreg); T93C46_Clk(np, gpreg);
*read_bit = INB (nc_gpreg); *read_bit = INB(np, nc_gpreg);
} }
/* /*
...@@ -573,8 +573,8 @@ static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gp ...@@ -573,8 +573,8 @@ static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gp
*gpreg |= 0x10; *gpreg |= 0x10;
OUTB (nc_gpreg, *gpreg); OUTB(np, nc_gpreg, *gpreg);
UDELAY (2); udelay(2);
T93C46_Clk(np, gpreg); T93C46_Clk(np, gpreg);
} }
...@@ -585,8 +585,8 @@ static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gp ...@@ -585,8 +585,8 @@ static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gp
static void T93C46_Stop(struct sym_device *np, u_char *gpreg) static void T93C46_Stop(struct sym_device *np, u_char *gpreg)
{ {
*gpreg &= 0xef; *gpreg &= 0xef;
OUTB (nc_gpreg, *gpreg); OUTB(np, nc_gpreg, *gpreg);
UDELAY (2); udelay(2);
T93C46_Clk(np, gpreg); T93C46_Clk(np, gpreg);
} }
...@@ -603,7 +603,7 @@ static void T93C46_Send_Command(struct sym_device *np, u_short write_data, ...@@ -603,7 +603,7 @@ static void T93C46_Send_Command(struct sym_device *np, u_short write_data,
for (x = 0; x < 9; x++) for (x = 0; x < 9; x++)
T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
*read_bit = INB (nc_gpreg); *read_bit = INB(np, nc_gpreg);
} }
/* /*
...@@ -657,23 +657,23 @@ static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram) ...@@ -657,23 +657,23 @@ static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram)
int retv = 1; int retv = 1;
/* save current state of GPCNTL and GPREG */ /* save current state of GPCNTL and GPREG */
old_gpreg = INB (nc_gpreg); old_gpreg = INB(np, nc_gpreg);
old_gpcntl = INB (nc_gpcntl); old_gpcntl = INB(np, nc_gpcntl);
/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
1/2/4 out */ 1/2/4 out */
gpreg = old_gpreg & 0xe9; gpreg = old_gpreg & 0xe9;
OUTB (nc_gpreg, gpreg); OUTB(np, nc_gpreg, gpreg);
gpcntl = (old_gpcntl & 0xe9) | 0x09; gpcntl = (old_gpcntl & 0xe9) | 0x09;
OUTB (nc_gpcntl, gpcntl); OUTB(np, nc_gpcntl, gpcntl);
/* input all of NVRAM, 64 words */ /* input all of NVRAM, 64 words */
retv = T93C46_Read_Data(np, (u_short *) nvram, retv = T93C46_Read_Data(np, (u_short *) nvram,
sizeof(*nvram) / sizeof(short), &gpreg); sizeof(*nvram) / sizeof(short), &gpreg);
/* return GPIO0/1/2/4 to original states after having accessed NVRAM */ /* return GPIO0/1/2/4 to original states after having accessed NVRAM */
OUTB (nc_gpcntl, old_gpcntl); OUTB(np, nc_gpcntl, old_gpcntl);
OUTB (nc_gpreg, old_gpreg); OUTB(np, nc_gpreg, old_gpreg);
return retv; return retv;
} }
...@@ -755,3 +755,17 @@ int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp) ...@@ -755,3 +755,17 @@ int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
} }
return nvp->type; return nvp->type;
} }
char *sym_nvram_type(struct sym_nvram *nvp)
{
switch (nvp->type) {
case SYM_SYMBIOS_NVRAM:
return "Symbios NVRAM";
case SYM_TEKRAM_NVRAM:
return "Tekram NVRAM";
case SYM_PARISC_PDC:
return "PA-RISC Firmware";
default:
return "No NVRAM";
}
}
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
#ifndef SYM_NVRAM_H #ifndef SYM_NVRAM_H
#define SYM_NVRAM_H #define SYM_NVRAM_H
#include "sym_conf.h" #include "sym53c8xx.h"
/* /*
* Symbios NVRAM data format * Symbios NVRAM data format
...@@ -193,17 +193,22 @@ struct sym_nvram { ...@@ -193,17 +193,22 @@ struct sym_nvram {
}; };
#if SYM_CONF_NVRAM_SUPPORT #if SYM_CONF_NVRAM_SUPPORT
void sym_nvram_setup_host (struct sym_hcb *np, struct sym_nvram *nvram); void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram);
void sym_nvram_setup_target (struct sym_hcb *np, int target, struct sym_nvram *nvp); void sym_nvram_setup_target (struct sym_hcb *np, int target, struct sym_nvram *nvp);
int sym_read_nvram (struct sym_device *np, struct sym_nvram *nvp); int sym_read_nvram (struct sym_device *np, struct sym_nvram *nvp);
char *sym_nvram_type(struct sym_nvram *nvp);
#else #else
static inline void sym_nvram_setup_host(struct sym_hcb *np, struct sym_nvram *nvram) { } static inline void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) { }
static inline void sym_nvram_setup_target(struct sym_hcb *np, struct sym_nvram *nvram) { } static inline void sym_nvram_setup_target(struct sym_hcb *np, struct sym_nvram *nvram) { }
static inline int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp) static inline int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
{ {
nvp->type = 0; nvp->type = 0;
return 0; return 0;
} }
static inline char *sym_nvram_type(struct sym_nvram *nvp)
{
return "No NVRAM";
}
#endif #endif
#endif /* SYM_NVRAM_H */ #endif /* SYM_NVRAM_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment