Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8b12f0f authored by Mahesh Rajashekhara's avatar Mahesh Rajashekhara Committed by James Bottomley
Browse files

[SCSI] aacraid: Add new code for PMC-Sierra's SRC based controller family



Added new hardware device 0x28b interface for PMC-Sierra's SRC based
controller family.

- new src.c file for 0x28b specific functions
- new XPORT header required
- sync. command interface: doorbell bits shifted (SRC_ODR_SHIFT, SRC_IDR_SHIFT)
- async. Interface: different inbound queue handling, no outbound I2O
  queue available, using doorbell ("PmDoorBellResponseSent") and
  response buffer on the host ("host_rrq") for status
- changed AIF (adapter initiated FIBs) interface: "DoorBellAifPending"
  bit to inform about pending AIF, "AifRequest" command to read AIF,
  "NoMoreAifDataAvailable" to mark the end of the AIFs

Signed-off-by: default avatarMahesh Rajashekhara <aacraid@pmc-sierra.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent 0a2385ce
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -3,6 +3,6 @@
obj-$(CONFIG_SCSI_AACRAID) := aacraid.o

aacraid-objs	:= linit.o aachba.o commctrl.o comminit.o commsup.o \
		   dpcsup.o rx.o sa.o rkt.o nark.o
		   dpcsup.o rx.o sa.o rkt.o nark.o src.o

ccflags-y	:= -Idrivers/scsi
+5 −2
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@
 * based on the old aacraid driver that is..
 * Adaptec aacraid device driver for Linux.
 *
 * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
 * Copyright (c) 2000-2010 Adaptec, Inc.
 *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
 *
 * 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
@@ -1486,6 +1487,8 @@ int aac_get_adapter_info(struct aac_dev* dev)
			dev->a_ops.adapter_write = aac_write_block;
		}
		dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT;
		if (dev->adapter_info.options & AAC_OPT_NEW_COMM_TYPE1)
			dev->adapter_info.options |= AAC_OPT_NEW_COMM;
		if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) {
			/*
			 * Worst case size that could cause sg overflow when
+96 −10
Original line number Diff line number Diff line
@@ -12,7 +12,7 @@
 *----------------------------------------------------------------------------*/

#ifndef AAC_DRIVER_BUILD
# define AAC_DRIVER_BUILD 26400
# define AAC_DRIVER_BUILD 28000
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS	32
@@ -277,6 +277,16 @@ enum aac_queue_types {

#define		FsaNormal	1

/* transport FIB header (PMC) */
struct aac_fib_xporthdr {
	u64	HostAddress;	/* FIB host address w/o xport header */
	u32	Size;		/* FIB size excluding xport header */
	u32	Handle;		/* driver handle to reference the FIB */
	u64	Reserved[2];
};

#define		ALIGN32		32

/*
 * Define the FIB. The FIB is the where all the requested data and
 * command information are put to the application on the FSA adapter.
@@ -394,7 +404,9 @@ enum fib_xfer_state {
	AdapterMicroFib			= (1<<17),
	BIOSFibPath			= (1<<18),
	FastResponseCapable		= (1<<19),
	ApiFib				= (1<<20)	// Its an API Fib.
	ApiFib				= (1<<20),	/* Its an API Fib */
	/* PMC NEW COMM: There is no more AIF data pending */
	NoMoreAifDataAvailable		= (1<<21)
};

/*
@@ -404,6 +416,7 @@ enum fib_xfer_state {

#define ADAPTER_INIT_STRUCT_REVISION		3
#define ADAPTER_INIT_STRUCT_REVISION_4		4 // rocket science
#define ADAPTER_INIT_STRUCT_REVISION_6		6 /* PMC src */

struct aac_init
{
@@ -428,9 +441,15 @@ struct aac_init
#define INITFLAGS_NEW_COMM_SUPPORTED	0x00000001
#define INITFLAGS_DRIVER_USES_UTC_TIME	0x00000010
#define INITFLAGS_DRIVER_SUPPORTS_PM	0x00000020
#define INITFLAGS_NEW_COMM_TYPE1_SUPPORTED	0x00000041
	__le32	MaxIoCommands;	/* max outstanding commands */
	__le32	MaxIoSize;	/* largest I/O command */
	__le32	MaxFibSize;	/* largest FIB to adapter */
	/* ADAPTER_INIT_STRUCT_REVISION_5 begins here */
	__le32	MaxNumAif;	/* max number of aif */
	/* ADAPTER_INIT_STRUCT_REVISION_6 begins here */
	__le32	HostRRQ_AddrLow;
	__le32	HostRRQ_AddrHigh;	/* Host RRQ (response queue) for SRC */
};

enum aac_log_level {
@@ -685,7 +704,7 @@ struct rx_inbound {
#define OutboundDoorbellReg	MUnit.ODR

struct rx_registers {
	struct rx_mu_registers		MUnit;		/* 1300h - 1344h */
	struct rx_mu_registers		MUnit;		/* 1300h - 1347h */
	__le32				reserved1[2];	/* 1348h - 134ch */
	struct rx_inbound		IndexRegs;
};
@@ -703,7 +722,7 @@ struct rx_registers {
#define rkt_inbound rx_inbound

struct rkt_registers {
	struct rkt_mu_registers		MUnit;		 /* 1300h - 1344h */
	struct rkt_mu_registers		MUnit;		 /* 1300h - 1347h */
	__le32				reserved1[1006]; /* 1348h - 22fch */
	struct rkt_inbound		IndexRegs;	 /* 2300h - */
};
@@ -713,6 +732,44 @@ struct rkt_registers {
#define rkt_writeb(AEP, CSR, value)	writeb(value, &((AEP)->regs.rkt->CSR))
#define rkt_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.rkt->CSR))

/*
 * PMC SRC message unit registers
 */

#define src_inbound rx_inbound

struct src_mu_registers {
				/*	PCI*| Name */
	__le32	reserved0[8];	/*	00h | Reserved */
	__le32	IDR;		/*	20h | Inbound Doorbell Register */
	__le32	IISR;		/*	24h | Inbound Int. Status Register */
	__le32	reserved1[3];	/*	28h | Reserved */
	__le32	OIMR;		/*	34h | Outbound Int. Mask Register */
	__le32	reserved2[25];	/*	38h | Reserved */
	__le32	ODR_R;		/*	9ch | Outbound Doorbell Read */
	__le32	ODR_C;		/*	a0h | Outbound Doorbell Clear */
	__le32	reserved3[6];	/*	a4h | Reserved */
	__le32	OMR;		/*	bch | Outbound Message Register */
	__le32	IQ_L;		/*  c0h | Inbound Queue (Low address) */
	__le32	IQ_H;		/*  c4h | Inbound Queue (High address) */
};

struct src_registers {
	struct src_mu_registers MUnit;	/* 00h - c7h */
	__le32 reserved1[130790];	/* c8h - 7fc5fh */
	struct src_inbound IndexRegs;	/* 7fc60h */
};

#define src_readb(AEP, CSR)		readb(&((AEP)->regs.src.bar0->CSR))
#define src_readl(AEP, CSR)		readl(&((AEP)->regs.src.bar0->CSR))
#define src_writeb(AEP, CSR, value)	writeb(value, \
						&((AEP)->regs.src.bar0->CSR))
#define src_writel(AEP, CSR, value)	writel(value, \
						&((AEP)->regs.src.bar0->CSR))

#define SRC_ODR_SHIFT		12
#define SRC_IDR_SHIFT		9

typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);

struct aac_fib_context {
@@ -879,6 +936,7 @@ struct aac_supplement_adapter_info
#define AAC_OPTION_MU_RESET		cpu_to_le32(0x00000001)
#define AAC_OPTION_IGNORE_RESET		cpu_to_le32(0x00000002)
#define AAC_OPTION_POWER_MANAGEMENT	cpu_to_le32(0x00000004)
#define AAC_OPTION_DOORBELL_RESET	cpu_to_le32(0x00004000)
#define AAC_SIS_VERSION_V3	3
#define AAC_SIS_SLOT_UNKNOWN	0xFF

@@ -940,6 +998,7 @@ struct aac_bus_info_response {
#define AAC_OPT_SUPPLEMENT_ADAPTER_INFO	cpu_to_le32(1<<16)
#define AAC_OPT_NEW_COMM		cpu_to_le32(1<<17)
#define AAC_OPT_NEW_COMM_64		cpu_to_le32(1<<18)
#define AAC_OPT_NEW_COMM_TYPE1		cpu_to_le32(1<<28)

struct aac_dev
{
@@ -952,6 +1011,7 @@ struct aac_dev
	 */
	unsigned		max_fib_size;
	unsigned		sg_tablesize;
	unsigned		max_num_aif;

	/*
	 *	Map for 128 fib objects (64k)
@@ -980,10 +1040,21 @@ struct aac_dev
	struct adapter_ops	a_ops;
	unsigned long		fsrev;		/* Main driver's revision number */

	unsigned		base_size;	/* Size of mapped in region */
	unsigned long		dbg_base;	/* address of UART
						 * debug buffer */

	unsigned		base_size, dbg_size;	/* Size of
							 *  mapped in region */

	struct aac_init		*init;		/* Holds initialization info to communicate with adapter */
	dma_addr_t		init_pa;	/* Holds physical address of the init struct */

	u32			*host_rrq;	/* response queue
						 * if AAC_COMM_MESSAGE_TYPE1 */

	dma_addr_t		host_rrq_pa;	/* phys. address */
	u32			host_rrq_idx;	/* index into rrq buffer */

	struct pci_dev		*pdev;		/* Our PCI interface */
	void *			printfbuf;	/* pointer to buffer used for printf's from the adapter */
	void *			comm_addr;	/* Base address of Comm area */
@@ -1003,14 +1074,20 @@ struct aac_dev
	 */
#ifndef AAC_MIN_FOOTPRINT_SIZE
#	define AAC_MIN_FOOTPRINT_SIZE 8192
#	define AAC_MIN_SRC_BAR0_SIZE 0x400000
#	define AAC_MIN_SRC_BAR1_SIZE 0x800
#endif
	union
	{
		struct sa_registers __iomem *sa;
		struct rx_registers __iomem *rx;
		struct rkt_registers __iomem *rkt;
		struct {
			struct src_registers __iomem *bar0;
			char __iomem *bar1;
		} src;
	} regs;
	volatile void __iomem *base;
	volatile void __iomem *base, *dbg_base_mapped;
	volatile struct rx_inbound __iomem *IndexRegs;
	u32			OIMR; /* Mask Register Cache */
	/*
@@ -1031,9 +1108,8 @@ struct aac_dev
	u8			comm_interface;
#	define AAC_COMM_PRODUCER 0
#	define AAC_COMM_MESSAGE  1
	/* macro side-effects BEWARE */
#	define			raw_io_interface \
	  init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4)
#	define AAC_COMM_MESSAGE_TYPE1	3
	u8			raw_io_interface;
	u8			raw_io_64;
	u8			printf_enabled;
	u8			in_reset;
@@ -1789,6 +1865,10 @@ extern struct aac_common aac_config;
#define DoorBellAdapterNormCmdNotFull	(1<<3)	/* Adapter -> Host */
#define DoorBellAdapterNormRespNotFull	(1<<4)	/* Adapter -> Host */
#define DoorBellPrintfReady		(1<<5)	/* Adapter -> Host */
#define DoorBellAifPending		(1<<6)	/* Adapter -> Host */

/* PMC specific outbound doorbell bits */
#define PmDoorBellResponseSent		(1<<1)	/* Adapter -> Host */

/*
 *	For FIB communication, we need all of the following things
@@ -1831,6 +1911,9 @@ extern struct aac_common aac_config;
#define		AifReqAPIJobUpdate	109	/* Update a job report from the API */
#define		AifReqAPIJobFinish	110	/* Finish a job from the API */

/* PMC NEW COMM: Request the event data */
#define		AifReqEvent		200

/*
 *	Adapter Initiated FIB command structures. Start with the adapter
 *	initiated FIBs that really come from the adapter, and get responded
@@ -1886,10 +1969,13 @@ int aac_rx_init(struct aac_dev *dev);
int aac_rkt_init(struct aac_dev *dev);
int aac_nark_init(struct aac_dev *dev);
int aac_sa_init(struct aac_dev *dev);
int aac_src_init(struct aac_dev *dev);
int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify);
unsigned int aac_response_normal(struct aac_queue * q);
unsigned int aac_command_normal(struct aac_queue * q);
unsigned int aac_intr_normal(struct aac_dev * dev, u32 Index);
unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index,
			int isAif, int isFastResponse,
			struct hw_fib *aif_fib);
int aac_reset_adapter(struct aac_dev * dev, int forced);
int aac_check_health(struct aac_dev * dev);
int aac_command_thread(void *data);
+2 −1
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@
 * based on the old aacraid driver that is..
 * Adaptec aacraid device driver for Linux.
 *
 * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
 * Copyright (c) 2000-2010 Adaptec, Inc.
 *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
 *
 * 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
+45 −13
Original line number Diff line number Diff line
@@ -5,7 +5,8 @@
 * based on the old aacraid driver that is..
 * Adaptec aacraid device driver for Linux.
 *
 * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com)
 * Copyright (c) 2000-2010 Adaptec, Inc.
 *               2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com)
 *
 * 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
@@ -52,12 +53,16 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
	unsigned long size, align;
	const unsigned long fibsize = 4096;
	const unsigned long printfbufsiz = 256;
	unsigned long host_rrq_size = 0;
	struct aac_init *init;
	dma_addr_t phys;
	unsigned long aac_max_hostphysmempages;

	size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz;

	if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1)
		host_rrq_size = (dev->scsi_host_ptr->can_queue
			+ AAC_NUM_MGT_FIB) * sizeof(u32);
	size = fibsize + sizeof(struct aac_init) + commsize +
			commalign + printfbufsiz + host_rrq_size;
 
	base = pci_alloc_consistent(dev->pdev, size, &phys);

@@ -70,8 +75,14 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
	dev->comm_phys = phys;
	dev->comm_size = size;
	
	dev->init = (struct aac_init *)(base + fibsize);
	dev->init_pa = phys + fibsize;
	if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) {
		dev->host_rrq = (u32 *)(base + fibsize);
		dev->host_rrq_pa = phys + fibsize;
		memset(dev->host_rrq, 0, host_rrq_size);
	}

	dev->init = (struct aac_init *)(base + fibsize + host_rrq_size);
	dev->init_pa = phys + fibsize + host_rrq_size;

	init = dev->init;

@@ -106,8 +117,13 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co

	init->InitFlags = 0;
	if (dev->comm_interface == AAC_COMM_MESSAGE) {
		init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
		init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
		dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
	} else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) {
		init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6);
		init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_TYPE1_SUPPORTED);
		dprintk((KERN_WARNING
			"aacraid: New Comm Interface type1 enabled\n"));
	}
	init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME |
				       INITFLAGS_DRIVER_SUPPORTS_PM);
@@ -115,11 +131,18 @@ static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long co
	init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
	init->MaxFibSize = cpu_to_le32(dev->max_fib_size);

	init->MaxNumAif = cpu_to_le32(dev->max_num_aif);
	init->HostRRQ_AddrHigh = (u32)((u64)dev->host_rrq_pa >> 32);
	init->HostRRQ_AddrLow = (u32)(dev->host_rrq_pa & 0xffffffff);


	/*
	 * Increment the base address by the amount already used
	 */
	base = base + fibsize + sizeof(struct aac_init);
	phys = (dma_addr_t)((ulong)phys + fibsize + sizeof(struct aac_init));
	base = base + fibsize + host_rrq_size + sizeof(struct aac_init);
	phys = (dma_addr_t)((ulong)phys + fibsize + host_rrq_size +
		sizeof(struct aac_init));

	/*
	 *	Align the beginning of Headers to commalign
	 */
@@ -314,15 +337,22 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
		- sizeof(struct aac_write) + sizeof(struct sgentry))
			/ sizeof(struct sgentry);
	dev->comm_interface = AAC_COMM_PRODUCER;
	dev->raw_io_64 = 0;
	dev->raw_io_interface = dev->raw_io_64 = 0;

	if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES,
		0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) &&
	 		(status[0] == 0x00000001)) {
		if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64))
			dev->raw_io_64 = 1;
		if (dev->a_ops.adapter_comm &&
		    (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)))
		if (dev->a_ops.adapter_comm) {
			if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1)) {
				dev->comm_interface = AAC_COMM_MESSAGE_TYPE1;
				dev->raw_io_interface = 1;
			} else if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM)) {
				dev->comm_interface = AAC_COMM_MESSAGE;
				dev->raw_io_interface = 1;
			}
		}
		if ((dev->comm_interface == AAC_COMM_MESSAGE) &&
		    (status[2] > dev->base_size)) {
			aac_adapter_ioremap(dev, 0);
@@ -350,10 +380,12 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev)
		 *	status[3] & 0xFFFF	maximum number FIBs outstanding
		 */
		host->max_sectors = (status[1] >> 16) << 1;
		dev->max_fib_size = status[1] & 0xFFFF;
		/* Multiple of 32 for PMC */
		dev->max_fib_size = status[1] & 0xFFE0;
		host->sg_tablesize = status[2] >> 16;
		dev->sg_tablesize = status[2] & 0xFFFF;
		host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB;
		dev->max_num_aif = status[4] & 0xFFFF;
		/*
		 *	NOTE:
		 *	All these overrides are based on a fixed internal
Loading