linux/drivers/scsi/mvsas/mv_sas.h

485 lines
14 KiB
C
Raw Normal View History

/*
* Marvell 88SE64xx/88SE94xx main function head file
*
* Copyright 2007 Red Hat, Inc.
* Copyright 2008 Marvell. <kewei@marvell.com>
* Copyright 2009-2011 Marvell. <yuxiangl@marvell.com>
*
* This file is licensed under GPLv2.
*
* 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; version 2 of the
* License.
*
* 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 _MV_SAS_H_
#define _MV_SAS_H_
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/ctype.h>
#include <linux/dma-mapping.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h percpu.h is included by sched.h and module.h and thus ends up being included when building most .c files. percpu.h includes slab.h which in turn includes gfp.h making everything defined by the two files universally available and complicating inclusion dependencies. percpu.h -> slab.h dependency is about to be removed. Prepare for this change by updating users of gfp and slab facilities include those headers directly instead of assuming availability. As this conversion needs to touch large number of source files, the following script is used as the basis of conversion. http://userweb.kernel.org/~tj/misc/slabh-sweep.py The script does the followings. * Scan files for gfp and slab usages and update includes such that only the necessary includes are there. ie. if only gfp is used, gfp.h, if slab is used, slab.h. * When the script inserts a new include, it looks at the include blocks and try to put the new include such that its order conforms to its surrounding. It's put in the include block which contains core kernel includes, in the same order that the rest are ordered - alphabetical, Christmas tree, rev-Xmas-tree or at the end if there doesn't seem to be any matching order. * If the script can't find a place to put a new include (mostly because the file doesn't have fitting include block), it prints out an error message indicating which .h file needs to be added to the file. The conversion was done in the following steps. 1. The initial automatic conversion of all .c files updated slightly over 4000 files, deleting around 700 includes and adding ~480 gfp.h and ~3000 slab.h inclusions. The script emitted errors for ~400 files. 2. Each error was manually checked. Some didn't need the inclusion, some needed manual addition while adding it to implementation .h or embedding .c file was more appropriate for others. This step added inclusions to around 150 files. 3. The script was run again and the output was compared to the edits from #2 to make sure no file was left behind. 4. Several build tests were done and a couple of problems were fixed. e.g. lib/decompress_*.c used malloc/free() wrappers around slab APIs requiring slab.h to be added manually. 5. The script was run on all .h files but without automatically editing them as sprinkling gfp.h and slab.h inclusions around .h files could easily lead to inclusion dependency hell. Most gfp.h inclusion directives were ignored as stuff from gfp.h was usually wildly available and often used in preprocessor macros. Each slab.h inclusion directive was examined and added manually as necessary. 6. percpu.h was updated not to include slab.h. 7. Build test were done on the following configurations and failures were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my distributed build env didn't work with gcov compiles) and a few more options had to be turned off depending on archs to make things build (like ipr on powerpc/64 which failed due to missing writeq). * x86 and x86_64 UP and SMP allmodconfig and a custom test config. * powerpc and powerpc64 SMP allmodconfig * sparc and sparc64 SMP allmodconfig * ia64 SMP allmodconfig * s390 SMP allmodconfig * alpha SMP allmodconfig * um on x86_64 SMP allmodconfig 8. percpu.h modifications were reverted so that it could be applied as a separate patch and serve as bisection point. Given the fact that I had only a couple of failures from tests on step 6, I'm fairly confident about the coverage of this conversion patch. If there is a breakage, it's likely to be something in one of the arch headers which should be easily discoverable easily on most builds of the specific arch. Signed-off-by: Tejun Heo <tj@kernel.org> Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
#include <linux/slab.h>
#include <linux/vmalloc.h>
[SCSI] mvsas: Fix kernel panic on tile due to unaligned data access slot->response is a 64 bit quantity (and accessed as such), but its alignment is only 32 bits. This doesn't cause a problem on x86, but apparently causes a kernel panic on Tile: Stack dump complete Kernel panic - not syncing: Kernel unalign fault running the idle task! Starting stack dump of tid 0, pid 0 (swapper) on cpu 1 at cycle 341586172541 frame 0: 0xfffffff700140ee0 dump_stack+0x0/0x20 (sp 0xfffffe43ffedf420) frame 1: 0xfffffff700283270 panic+0x150/0x3a0 (sp 0xfffffe43ffedf420) frame 2: 0xfffffff70012bff8 jit_bundle_gen+0xfd8/0x27e0 (sp 0xfffffe43ffedf4c8) frame 3: 0xfffffff7003b5b68 do_unaligned+0xc0/0x5a0 (sp 0xfffffe43ffedf710) frame 4: 0xfffffff70044ca78 handle_interrupt+0x270/0x278 (sp 0xfffffe43ffedf840) <interrupt 17 while in kernel mode> frame 5: 0xfffffff7002ac370 mvs_slot_complete+0x5f0/0x12a0 (sp 0xfffffe43ffedfa90) frame 6: 0xfffffff7002abec0 mvs_slot_complete+0x140/0x12a0 (sp 0xfffffe43ffedfa90) frame 7: 0xfffffff7005cc840 mvs_int_rx+0x140/0x2a0 (sp 0xfffffe43ffedfb00) frame 8: 0xfffffff7005bbaf0 mvs_94xx_isr+0xd8/0x2b8 (sp 0xfffffe43ffedfb68) frame 9: 0xfffffff700658ba0 mvs_tasklet+0x128/0x1f8 (sp 0xfffffe43ffedfba8) frame 10: 0xfffffff7003e8230 tasklet_action+0x178/0x2c8 (sp 0xfffffe43ffedfbe0) frame 11: 0xfffffff700103850 __do_softirq+0x210/0x398 (sp 0xfffffe43ffedfc40) frame 12: 0xfffffff700180308 do_softirq+0xc8/0x140 (sp 0xfffffe43ffedfcd8) frame 13: 0xfffffff7000bd7f0 irq_exit+0xb0/0x158 (sp 0xfffffe43ffedfcf0) frame 14: 0xfffffff70013fa58 tile_dev_intr+0x1d8/0x2f0 (sp 0xfffffe43ffedfd00) frame 15: 0xfffffff70044ca78 handle_interrupt+0x270/0x278 (sp 0xfffffe43ffedfd40) <interrupt 30 while in kernel mode> frame 16: 0xfffffff700143e68 _cpu_idle_nap+0x0/0x18 (sp 0xfffffe43ffedffb0) frame 17: 0xfffffff700482480 cpu_idle+0x310/0x428 (sp 0xfffffe43ffedffb0) Since the check is just for non-zero, split it to be two 32 bit accesses (preserving speed in the fast path) and do a get_unaligned() in the slow path. This is a modification of a wholly get_unaligned patch submitted by Paul Guo Reported-by: Paul Guo <ggang@tilera.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
2013-06-10 00:23:16 +08:00
#include <asm/unaligned.h>
#include <scsi/libsas.h>
#include <scsi/scsi.h>
#include <scsi/scsi_tcq.h>
#include <scsi/sas_ata.h>
#include "mv_defs.h"
#define DRV_NAME "mvsas"
#define DRV_VERSION "0.8.16"
#define MVS_ID_NOT_MAPPED 0x7f
#define WIDE_PORT_MAX_PHY 4
#define mv_printk(fmt, arg ...) \
printk(KERN_DEBUG"%s %d:" fmt, __FILE__, __LINE__, ## arg)
#ifdef MV_DEBUG
#define mv_dprintk(format, arg...) \
printk(KERN_DEBUG"%s %d:" format, __FILE__, __LINE__, ## arg)
#else
#define mv_dprintk(format, arg...)
#endif
#define MV_MAX_U32 0xffffffff
extern int interrupt_coalescing;
extern struct mvs_tgt_initiator mvs_tgt;
extern struct mvs_info *tgt_mvi;
extern const struct mvs_dispatch mvs_64xx_dispatch;
extern const struct mvs_dispatch mvs_94xx_dispatch;
#define DEV_IS_EXPANDER(type) \
((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE))
#define bit(n) ((u64)1 << n)
#define for_each_phy(__lseq_mask, __mc, __lseq) \
for ((__mc) = (__lseq_mask), (__lseq) = 0; \
(__mc) != 0 ; \
(++__lseq), (__mc) >>= 1)
#define MVS_PHY_ID (1U << sas_phy->id)
#define MV_INIT_DELAYED_WORK(w, f, d) INIT_DELAYED_WORK(w, f)
#define UNASSOC_D2H_FIS(id) \
((void *) mvi->rx_fis + 0x100 * id)
#define SATA_RECEIVED_FIS_LIST(reg_set) \
((void *) mvi->rx_fis + mvi->chip->fis_offs + 0x100 * reg_set)
#define SATA_RECEIVED_SDB_FIS(reg_set) \
(SATA_RECEIVED_FIS_LIST(reg_set) + 0x58)
#define SATA_RECEIVED_D2H_FIS(reg_set) \
(SATA_RECEIVED_FIS_LIST(reg_set) + 0x40)
#define SATA_RECEIVED_PIO_FIS(reg_set) \
(SATA_RECEIVED_FIS_LIST(reg_set) + 0x20)
#define SATA_RECEIVED_DMA_FIS(reg_set) \
(SATA_RECEIVED_FIS_LIST(reg_set) + 0x00)
enum dev_status {
MVS_DEV_NORMAL = 0x0,
MVS_DEV_EH = 0x1,
};
enum dev_reset {
MVS_SOFT_RESET = 0,
MVS_HARD_RESET = 1,
MVS_PHY_TUNE = 2,
};
struct mvs_info;
struct mvs_prv_info;
struct mvs_dispatch {
char *name;
int (*chip_init)(struct mvs_info *mvi);
int (*spi_init)(struct mvs_info *mvi);
int (*chip_ioremap)(struct mvs_info *mvi);
void (*chip_iounmap)(struct mvs_info *mvi);
irqreturn_t (*isr)(struct mvs_info *mvi, int irq, u32 stat);
u32 (*isr_status)(struct mvs_info *mvi, int irq);
void (*interrupt_enable)(struct mvs_info *mvi);
void (*interrupt_disable)(struct mvs_info *mvi);
u32 (*read_phy_ctl)(struct mvs_info *mvi, u32 port);
void (*write_phy_ctl)(struct mvs_info *mvi, u32 port, u32 val);
u32 (*read_port_cfg_data)(struct mvs_info *mvi, u32 port);
void (*write_port_cfg_data)(struct mvs_info *mvi, u32 port, u32 val);
void (*write_port_cfg_addr)(struct mvs_info *mvi, u32 port, u32 addr);
u32 (*read_port_vsr_data)(struct mvs_info *mvi, u32 port);
void (*write_port_vsr_data)(struct mvs_info *mvi, u32 port, u32 val);
void (*write_port_vsr_addr)(struct mvs_info *mvi, u32 port, u32 addr);
u32 (*read_port_irq_stat)(struct mvs_info *mvi, u32 port);
void (*write_port_irq_stat)(struct mvs_info *mvi, u32 port, u32 val);
u32 (*read_port_irq_mask)(struct mvs_info *mvi, u32 port);
void (*write_port_irq_mask)(struct mvs_info *mvi, u32 port, u32 val);
void (*command_active)(struct mvs_info *mvi, u32 slot_idx);
void (*clear_srs_irq)(struct mvs_info *mvi, u8 reg_set, u8 clear_all);
void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type,
u32 tfs);
void (*start_delivery)(struct mvs_info *mvi, u32 tx);
u32 (*rx_update)(struct mvs_info *mvi);
void (*int_full)(struct mvs_info *mvi);
u8 (*assign_reg_set)(struct mvs_info *mvi, u8 *tfs);
void (*free_reg_set)(struct mvs_info *mvi, u8 *tfs);
u32 (*prd_size)(void);
u32 (*prd_count)(void);
void (*make_prd)(struct scatterlist *scatter, int nr, void *prd);
void (*detect_porttype)(struct mvs_info *mvi, int i);
int (*oob_done)(struct mvs_info *mvi, int i);
void (*fix_phy_info)(struct mvs_info *mvi, int i,
struct sas_identify_frame *id);
void (*phy_work_around)(struct mvs_info *mvi, int i);
void (*phy_set_link_rate)(struct mvs_info *mvi, u32 phy_id,
struct sas_phy_linkrates *rates);
u32 (*phy_max_link_rate)(void);
void (*phy_disable)(struct mvs_info *mvi, u32 phy_id);
void (*phy_enable)(struct mvs_info *mvi, u32 phy_id);
void (*phy_reset)(struct mvs_info *mvi, u32 phy_id, int hard);
void (*stp_reset)(struct mvs_info *mvi, u32 phy_id);
void (*clear_active_cmds)(struct mvs_info *mvi);
u32 (*spi_read_data)(struct mvs_info *mvi);
void (*spi_write_data)(struct mvs_info *mvi, u32 data);
int (*spi_buildcmd)(struct mvs_info *mvi,
u32 *dwCmd,
u8 cmd,
u8 read,
u8 length,
u32 addr
);
int (*spi_issuecmd)(struct mvs_info *mvi, u32 cmd);
int (*spi_waitdataready)(struct mvs_info *mvi, u32 timeout);
void (*dma_fix)(struct mvs_info *mvi, u32 phy_mask,
int buf_len, int from, void *prd);
void (*tune_interrupt)(struct mvs_info *mvi, u32 time);
void (*non_spec_ncq_error)(struct mvs_info *mvi);
int (*gpio_write)(struct mvs_prv_info *mvs_prv, u8 reg_type,
u8 reg_index, u8 reg_count, u8 *write_data);
};
struct mvs_chip_info {
u32 n_host;
u32 n_phy;
u32 fis_offs;
u32 fis_count;
u32 srs_sz;
u32 sg_width;
u32 slot_width;
const struct mvs_dispatch *dispatch;
};
#define MVS_MAX_SG (1U << mvi->chip->sg_width)
#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width)
#define MVS_RX_FISL_SZ \
(mvi->chip->fis_offs + (mvi->chip->fis_count * 0x100))
#define MVS_CHIP_DISP (mvi->chip->dispatch)
struct mvs_err_info {
__le32 flags;
__le32 flags2;
};
struct mvs_cmd_hdr {
__le32 flags; /* PRD tbl len; SAS, SATA ctl */
__le32 lens; /* cmd, max resp frame len */
__le32 tags; /* targ port xfer tag; tag */
__le32 data_len; /* data xfer len */
__le64 cmd_tbl; /* command table address */
__le64 open_frame; /* open addr frame address */
__le64 status_buf; /* status buffer address */
__le64 prd_tbl; /* PRD tbl address */
__le32 reserved[4];
};
struct mvs_port {
struct asd_sas_port sas_port;
u8 port_attached;
u8 wide_port_phymap;
struct list_head list;
};
struct mvs_phy {
struct mvs_info *mvi;
struct mvs_port *port;
struct asd_sas_phy sas_phy;
struct sas_identify identify;
struct scsi_device *sdev;
struct timer_list timer;
u64 dev_sas_addr;
u64 att_dev_sas_addr;
u32 att_dev_info;
u32 dev_info;
u32 phy_type;
u32 phy_status;
u32 irq_status;
u32 frame_rcvd_size;
u8 frame_rcvd[32];
u8 phy_attached;
u8 phy_mode;
u8 reserved[2];
u32 phy_event;
enum sas_linkrate minimum_linkrate;
enum sas_linkrate maximum_linkrate;
};
struct mvs_device {
struct list_head dev_entry;
enum sas_device_type dev_type;
struct mvs_info *mvi_info;
struct domain_device *sas_device;
u32 attached_phy;
u32 device_id;
u32 running_req;
u8 taskfileset;
u8 dev_status;
u16 reserved;
};
/* Generate PHY tunning parameters */
struct phy_tuning {
/* 1 bit, transmitter emphasis enable */
u8 trans_emp_en:1;
/* 4 bits, transmitter emphasis amplitude */
u8 trans_emp_amp:4;
/* 3 bits, reserved space */
u8 Reserved_2bit_1:3;
/* 5 bits, transmitter amplitude */
u8 trans_amp:5;
/* 2 bits, transmitter amplitude adjust */
u8 trans_amp_adj:2;
/* 1 bit, reserved space */
u8 resv_2bit_2:1;
/* 2 bytes, reserved space */
u8 reserved[2];
};
struct ffe_control {
/* 4 bits, FFE Capacitor Select (value range 0~F) */
u8 ffe_cap_sel:4;
/* 3 bits, FFE Resistor Select (value range 0~7) */
u8 ffe_rss_sel:3;
/* 1 bit reserve*/
u8 reserved:1;
};
/*
* HBA_Info_Page is saved in Flash/NVRAM, total 256 bytes.
* The data area is valid only Signature="MRVL".
* If any member fills with 0xFF, the member is invalid.
*/
struct hba_info_page {
/* Dword 0 */
/* 4 bytes, structure signature,should be "MRVL" at first initial */
u8 signature[4];
/* Dword 1-13 */
u32 reserved1[13];
/* Dword 14-29 */
/* 64 bytes, SAS address for each port */
u64 sas_addr[8];
/* Dword 30-31 */
/* 8 bytes for vanir 8 port PHY FFE seeting
* BIT 0~3 : FFE Capacitor select(value range 0~F)
* BIT 4~6 : FFE Resistor select(value range 0~7)
* BIT 7: reserve.
*/
struct ffe_control ffe_ctl[8];
/* Dword 32 -43 */
u32 reserved2[12];
/* Dword 44-45 */
/* 8 bytes, 0: 1.5G, 1: 3.0G, should be 0x01 at first initial */
u8 phy_rate[8];
/* Dword 46-53 */
/* 32 bytes, PHY tuning parameters for each PHY*/
struct phy_tuning phy_tuning[8];
/* Dword 54-63 */
u32 reserved3[10];
}; /* total 256 bytes */
struct mvs_slot_info {
struct list_head entry;
union {
struct sas_task *task;
void *tdata;
};
u32 n_elem;
u32 tx;
u32 slot_tag;
/* DMA buffer for storing cmd tbl, open addr frame, status buffer,
* and PRD table
*/
void *buf;
dma_addr_t buf_dma;
void *response;
struct mvs_port *port;
struct mvs_device *device;
void *open_frame;
};
struct mvs_info {
unsigned long flags;
/* host-wide lock */
spinlock_t lock;
/* our device */
struct pci_dev *pdev;
struct device *dev;
/* enhanced mode registers */
void __iomem *regs;
/* peripheral or soc registers */
void __iomem *regs_ex;
u8 sas_addr[SAS_ADDR_SIZE];
/* SCSI/SAS glue */
struct sas_ha_struct *sas;
struct Scsi_Host *shost;
/* TX (delivery) DMA ring */
__le32 *tx;
dma_addr_t tx_dma;
/* cached next-producer idx */
u32 tx_prod;
/* RX (completion) DMA ring */
__le32 *rx;
dma_addr_t rx_dma;
/* RX consumer idx */
u32 rx_cons;
/* RX'd FIS area */
__le32 *rx_fis;
dma_addr_t rx_fis_dma;
/* DMA command header slots */
struct mvs_cmd_hdr *slot;
dma_addr_t slot_dma;
u32 chip_id;
const struct mvs_chip_info *chip;
int tags_num;
unsigned long *tags;
/* further per-slot information */
struct mvs_phy phy[MVS_MAX_PHYS];
struct mvs_port port[MVS_MAX_PHYS];
u32 id;
u64 sata_reg_set;
struct list_head *hba_list;
struct list_head soc_entry;
struct list_head wq_list;
unsigned long instance;
u16 flashid;
u32 flashsize;
u32 flashsectSize;
void *addon;
struct hba_info_page hba_info_param;
struct mvs_device devices[MVS_MAX_DEVICES];
void *bulk_buffer;
dma_addr_t bulk_buffer_dma;
void *bulk_buffer1;
dma_addr_t bulk_buffer_dma1;
#define TRASH_BUCKET_SIZE 0x20000
void *dma_pool;
struct mvs_slot_info slot_info[0];
};
struct mvs_prv_info{
u8 n_host;
u8 n_phy;
u8 scan_finished;
u8 reserve;
struct mvs_info *mvi[2];
struct tasklet_struct mv_tasklet;
};
struct mvs_wq {
struct delayed_work work_q;
struct mvs_info *mvi;
void *data;
int handler;
struct list_head entry;
};
struct mvs_task_exec_info {
struct sas_task *task;
struct mvs_cmd_hdr *hdr;
struct mvs_port *port;
u32 tag;
int n_elem;
};
/******************** function prototype *********************/
void mvs_get_sas_addr(void *buf, u32 buflen);
void mvs_tag_clear(struct mvs_info *mvi, u32 tag);
void mvs_tag_free(struct mvs_info *mvi, u32 tag);
void mvs_tag_set(struct mvs_info *mvi, unsigned int tag);
int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out);
void mvs_tag_init(struct mvs_info *mvi);
void mvs_iounmap(void __iomem *regs);
int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex);
void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard);
int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
void *funcdata);
void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo,
u32 off_hi, u64 sas_addr);
void mvs_scan_start(struct Scsi_Host *shost);
int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time);
int mvs_queue_command(struct sas_task *task, gfp_t gfp_flags);
int mvs_abort_task(struct sas_task *task);
int mvs_abort_task_set(struct domain_device *dev, u8 *lun);
int mvs_clear_aca(struct domain_device *dev, u8 *lun);
int mvs_clear_task_set(struct domain_device *dev, u8 * lun);
void mvs_port_formed(struct asd_sas_phy *sas_phy);
void mvs_port_deformed(struct asd_sas_phy *sas_phy);
int mvs_dev_found(struct domain_device *dev);
void mvs_dev_gone(struct domain_device *dev);
int mvs_lu_reset(struct domain_device *dev, u8 *lun);
int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags);
int mvs_I_T_nexus_reset(struct domain_device *dev);
int mvs_query_task(struct sas_task *task);
void mvs_release_task(struct mvs_info *mvi,
struct domain_device *dev);
void mvs_do_release_task(struct mvs_info *mvi, int phy_no,
struct domain_device *dev);
void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events);
void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st);
int mvs_int_rx(struct mvs_info *mvi, bool self_clear);
struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set);
int mvs_gpio_write(struct sas_ha_struct *, u8 reg_type, u8 reg_index,
u8 reg_count, u8 *write_data);
#endif