From be0eb86e2fa54d4642f94440c0cffdc365e07d1c Mon Sep 17 00:00:00 2001 From: Andy Yan Date: Thu, 18 Jun 2009 09:12:44 +0000 Subject: [PATCH] 1. Fixed deadlock issue. 2. Update code to support adaptable feature set according chip type. 3. Add support new B0 chip of 9480. 4. Add change log file and README git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@912 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- mvsas_tgt/ChangeLog | 61 +++++++++++++++++ mvsas_tgt/Makefile | 2 +- mvsas_tgt/README | 132 ++++++++++++++++++++++++++++++++++++ mvsas_tgt/mv_64xx.c | 4 +- mvsas_tgt/mv_94xx.c | 138 +++++++++++++++++++++++++++++++------- mvsas_tgt/mv_94xx.h | 9 ++- mvsas_tgt/mv_chips.h | 3 +- mvsas_tgt/mv_defs.h | 7 +- mvsas_tgt/mv_init.c | 90 ++++++++++++++++++------- mvsas_tgt/mv_sas.c | 156 +++++++++++++++++++++---------------------- mvsas_tgt/mv_sas.h | 7 +- mvsas_tgt/mv_spi.c | 2 + mvsas_tgt/mv_tgt.c | 21 +++--- 13 files changed, 481 insertions(+), 151 deletions(-) create mode 100644 mvsas_tgt/ChangeLog create mode 100644 mvsas_tgt/README diff --git a/mvsas_tgt/ChangeLog b/mvsas_tgt/ChangeLog new file mode 100644 index 000000000..d57646575 --- /dev/null +++ b/mvsas_tgt/ChangeLog @@ -0,0 +1,61 @@ +Summary of changes between versions 0.8.4 and 0.8.3 + - Fixed issue with working on big endian platform. + - Adjust code of supporting hardware feature accoring to chip type. + - Add supporting Vanir B0 chip. +---------------------------------------------------- +Summary of changes between versions 0.8.3 and 0.8.2 + - Add code to balance sata disk io stress on expander. + - Update scst to 1.0.1 and enhance task management function of target driver. + - Change wide port load balance scheme. + - Enable interrupt coalescing. +---------------------------------------------------- +Summary of changes between versions 0.8.2 and 0.8.1 + - Fixed issue - Wrong return value with smart control test. + - Add patch for libsas on port selector + - Fixed issue with error handling. +---------------------------------------------------- +Summary of changes between versions 0.8.1 and 0.7.10 + - Fixed issue -- Detecting SATA disk with hotplug in. + - Enhance error hanlding. +---------------------------------------------------- +Summary of changes between versions 0.7.10 and 0.7.9 + - Fixed issue -- System hang when stress test with SATA disk. +---------------------------------------------------- +Summary of changes between versions 0.7.9 and 0.7.8 + - Fixed issue -- Changed the code to report one scsi host for Vanir chip. +---------------------------------------------------- +Summary of changes between versions 0.7.8 and 0.7.7 + - Fixed issue -- Set max sg entry count according to chip specific for DMA fix. + - Fixed Libsas issue -- memory corruption issue. +--------------------------------------------------- +Summary of changes between versions 0.7.7 and 0.7.6 + - Fixed issue: Kernel panic with 64bit OS, structure change. + - Fixed issue: Kernel panic if hot plug any disk when run stress. + - Fixed issue: Add multiple LUN fail with some controller. + - Changed the interface for target mode enable. + - Add supporting target mode for new controller 91xx. +--------------------------------------------------- +Summary of changes between versions 0.7.6 and 0.7.5 + - Fixed issue -- Because of the different SAS address of HBA's phys, wide + port mode doesn't work. + - Fixed issue -- failed to discover SATA drive when plug out/in SATA disk which run + DD test. + +Summary of changes between versions 0.7.5 and 0.7.4 +--------------------------------------------------- + - Fixed issue -- PDs connected expander still can be detected after plug out the expander . + - Fixed issue -- PDs connected expander can not be detected after plug in the expander. + +Summary of changes between versions 0.7.4 and 0.7.3 +--------------------------------------------------- + - Fixed issue -- can not find SATA disk connected Vanir directly. + +Summary of changes between versions 0.7.3 and 0.7.2 +--------------------------------------------------- + - Support device id 11AB/9480. + - Update for 2.6.27 + - Fixed issue -- can not find SATA disk behind expander. + - Support read/write flash ROM for 9480/9180. + - Minor fixes and cleanups + + diff --git a/mvsas_tgt/Makefile b/mvsas_tgt/Makefile index de5d54e90..2352e146e 100644 --- a/mvsas_tgt/Makefile +++ b/mvsas_tgt/Makefile @@ -45,7 +45,7 @@ SCST_DIR := $(shell pwd)/scst/src EXTRA_CFLAGS += -I$(SCST_INC_DIR) -EXTRA_CFLAGS += #-DSUPPORT_TARGET +EXTRA_CFLAGS += -DSUPPORT_TARGET MODULE_NAME = mvsas_tgt EXTRA_CFLAGS += -DMV_DEBUG diff --git a/mvsas_tgt/README b/mvsas_tgt/README new file mode 100644 index 000000000..0b7dbb8e6 --- /dev/null +++ b/mvsas_tgt/README @@ -0,0 +1,132 @@ +LIBSAS driver for Marvell 88SE63xx/64xx/68xx/94xx SAS controller +====================================================== + +This driver consists from two parts: the target mode driver itself and +the changed initiator driver from Linux kernel, which is particularly +intended to perform all the initialization and shutdown tasks. This +driver was changed to provide the target mode support and all necessary +callbacks, but it's still capable to work as initiator mode only, +when a host acts as the initiator and the target simultaneously, is +supported as well. + +This version is compatible with SCST core version 1.0.0 and higher and +Linux kernel 2.6.25 and higher, which must include libsas module. + +The original initiator driver was taken from the kernel 2.6.25. + + +See also "ToDo" for list of known issues and unimplemented +features. + + +Installation: +------------ +Only vanilla kernels from kernel.org are supported, but it should work +on vendors' kernels, if you manage to successfully compile on them. The +main problem with vendor's kernels is that they often contain patches, +which will appear only in the next version of the vanilla kernel, +therefore it's quite hard to track such changes. Thus, if during +compilation for some vendor kernel your compiler complains about +redefinition of some symbol, you should either switch to vanilla kernel, +or change as necessary the corresponding to that symbol "#if +LINUX_VERSION_CODE" statement. + +At first, make sure that the link "/lib/modules/`you_kernel_version`/build" +points to the source code for your currently running kernel. + +Second, patch the libsas and then make libsas module to install in in your +currently running kernel, also you should add ATA support for libsas in the +kerenl if you want to support SATA device. + +The codes have included the SCST code for supportting target, you need patch +the kernel use the patch file in ./scst/kernel. To compile the target driver, +at first, build scst in scst directory, then insmod scst_disk.ko to support +real disk, insmod scst_vdisk.ko to support vdisk, etc. +then, you should make sure the make option SUPPORT_TARGET has been enabled +in Makefile of mvsas, and then type 'make' in mvsas/ subdirectory. It will build +mvsas.ko module. + +To install the target driver, type 'make install' in mvsas/ +subdirectory. The target driver will be installed in +/lib/modules/`you_kernel_version`/extra. To uninstall it, type 'make +uninstall'. + +After the drivers are loaded and adapters are successfully initialized by +the initiator driver, including firmware image load, you can type following +command to show the detailed phy info, +cat /sys/class/scsi_host/hostX/target_mode +X is the host number of the controller, then you can get the info like + +phy dev sas address attach dev type attach sas address target mode +0 5005043011ab004b SAS END DEVICE 5000c50008424415 0 +1 5005043011ab004b SAS END DEVICE 5000c500064c363d 0 +2 5005043011ab004b 0 0 +3 5005043011ab004b SAS END DEVICE 500000e0192a37e2 0 +4 5005043011ab0000 SAS EXPANDER 5000155d220bc23f 0 +5 5005043011ab0000 SAS EXPANDER 5000155d220bc23f 0 +6 5005043011ab0000 SAS EXPANDER 5000155d220bc23f 0 +7 5005043011ab0000 SAS EXPANDER 5000155d220bc23f 0 + +then you can choose the one phy to enable the target mode of it.The target +mode should be enabled/disable via a sysfs interface on a per card basis. Under +the appropriate scsi_host there is an entry 'target_mode', where you should +type command like: + +echo "enable X" >/sys/class/scsi_host/hostY/target_mode +echo "disable X" >/sys/class/scsi_host/hostY/target_mode + +X is the phy number, Y is the host number of controller. + +eg: echo "disable 1" >/sys/class/scsi_host/host4/target_mode + +when you try to enale one phy of the controller, driver will enable all the +phys which have the same SAS address. + +Then you should configure exported devices using the corresponding +interface of SCST core. you can configure the target group +as README file of SCST described, like: + +echo "add 1:0:1:0 0" >/proc/scsi_tgt/groups/Default/devices + +also you can delete a LUN from target, like: + +echo "del 1:0:1:0 0" >/proc/scsi_tgt/groups/Default/devices + +for details of configure target disk group, pleae refer to README of SCST. + +note: +1. Appropriate phy should be setted to target mode for initiator to detect + disks by this phy. +2. In example "add 2:0:0:0 1" the '1' is the LUN in the target, LUN 0 must + exist with a target. +3. When one device is added to target disk group, target driver will notify + initator the changing of the phy mode and arriving of the disk, but some + initiator driver don't support phy mode changing well, so 'rmmod' and + 'modprobe'/'insmod' the initiator driver is neccessary. + + +following is an example for configuring the target driver. + +> modprobe libsas +> insmod mvsas.ko +> echo 1 >/sys/class/scsi_host/host4/target_mode +> echo "add 4:0:0:0 0" >/proc/scsi_tgt/groups/Default/devices + +Compilation options +------------------- + +There are the following compilation options, that could be commented +in/out in Makefile: + + - CONFIG_SCST_DEBUG - turns on some debugging code, including some logging. + Makes the driver considerably bigger and slower, producing large amount of + log data. + + - CONFIG_SCST_TRACING - turns on ability to log events. Makes the driver + considerably bigger and leads to some performance loss. + + - MV_DEBUG - turns on some debugging code for target driver itself. + + + + diff --git a/mvsas_tgt/mv_64xx.c b/mvsas_tgt/mv_64xx.c index 90f168e63..5575ed66e 100644 --- a/mvsas_tgt/mv_64xx.c +++ b/mvsas_tgt/mv_64xx.c @@ -379,10 +379,10 @@ static int __devinit mvs_64xx_init(struct mvs_info *mvi) * it will make count 0. */ tmp = 0; - if (MVS_SLOTS > 0x1ff) + if (MVS_CHIP_SLOT_SZ > 0x1ff) mw32(MVS_INT_COAL, 0x1ff|COAL_EN); else - mw32(MVS_INT_COAL, MVS_SLOTS|COAL_EN); + mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN); tmp = 0x10400; mw32(MVS_INT_COAL_TMOUT, tmp); diff --git a/mvsas_tgt/mv_94xx.c b/mvsas_tgt/mv_94xx.c index 53a5f1999..fa4f7513d 100644 --- a/mvsas_tgt/mv_94xx.c +++ b/mvsas_tgt/mv_94xx.c @@ -57,6 +57,43 @@ static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id) mw32(MVS_PCS, tmp); } +static void mvs_94xx_stp_reset(struct mvs_info *mvi, u32 phy_id) +{ + void __iomem *regs = mvi->regs; + u32 reg, tmp; + + if (!(mvi->flags & MVF_FLAG_SOC)) { + if (phy_id < 4) + pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, ®); + else + pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, ®); + + } else + reg = mr32(MVS_PHY_CTL); + + tmp = reg; + if (phy_id < 4) + tmp |= (1U << phy_id) << PCTL_LINK_OFFS; + else + tmp |= (1U << (phy_id - 4)) << PCTL_LINK_OFFS; + + if (!(mvi->flags & MVF_FLAG_SOC)) { + if (phy_id < 4) { + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); + mdelay(10); + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg); + } else { + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); + mdelay(10); + pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, reg); + } + } else { + mw32(MVS_PHY_CTL, tmp); + mdelay(10); + mw32(MVS_PHY_CTL, reg); + } +} + static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) { u32 tmp; @@ -89,12 +126,24 @@ static void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id) static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id) { - mvs_write_port_vsr_addr(mvi, phy_id, 0x1B4); - mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1); - mvs_write_port_vsr_addr(mvi, phy_id, 0x104); - mvs_write_port_vsr_data(mvi, phy_id, 0x00018080); + u32 tmp; + if (mvi->pdev->revision == 0xa0) { + mvs_write_port_vsr_addr(mvi, phy_id, 0x000001b4); + mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1); + } + if (mvi->pdev->revision == 0x01) { + mvs_write_port_vsr_addr(mvi, phy_id, 0x00000144); + mvs_write_port_vsr_data(mvi, phy_id, 0x08001006); + mvs_write_port_vsr_addr(mvi, phy_id, 0x000001b4); + mvs_write_port_vsr_data(mvi, phy_id, 0x0000705f); + } + /* mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); mvs_write_port_vsr_data(mvi, phy_id, 0x00207fff); + */ + mvs_write_port_vsr_addr(mvi, phy_id, 0x00000008); + tmp = 0x4ffff; + mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff); } static int __devinit mvs_94xx_init(struct mvs_info *mvi) @@ -132,6 +181,21 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi) msleep(100); } + /* disable Multiplexing, enable phy implemented */ + mw32(MVS_PORTS_IMP, 0xFF); + + if (mvi->pdev->revision == 0xa0) { + mw32(MVS_PA_VSR_ADDR, 0x00000104); + mw32(MVS_PA_VSR_PORT, 0x00018080); + } + mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE8); + mw32(MVS_PA_VSR_PORT, 0x0084ffff); + if (mvi->pdev->revision == 0x01) { + mw32(MVS_PA_VSR_ADDR, 0x00000144); + mw32(MVS_PA_VSR_PORT, 0x08001006); + mw32(MVS_PA_VSR_ADDR, 0x000001b4); + mw32(MVS_PA_VSR_PORT, 0x0000705f); + } /* reset control */ mw32(MVS_PCS, 0); /* MVS_PCS */ mw32(MVS_STP_REG_SET_0, 0); @@ -140,15 +204,6 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi) /* init phys */ mvs_phy_hacks(mvi); - /* disable Multiplexing, enable phy implemented */ - mw32(MVS_PORTS_IMP, 0xFF); - - - mw32(MVS_PA_VSR_ADDR, 0x00000104); - mw32(MVS_PA_VSR_PORT, 0x00018080); - mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE8); - mw32(MVS_PA_VSR_PORT, 0x0084ffff); - /* set LED blink when IO*/ mw32(MVS_PA_VSR_ADDR, 0x00000030); tmp = mr32(MVS_PA_VSR_PORT); @@ -174,7 +229,7 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi) mvs_94xx_phy_disable(mvi, i); /* set phy local SAS address */ mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4, - (mvi->phy[i].dev_sas_addr)); + cpu_to_le64(mvi->phy[i].dev_sas_addr)); mvs_94xx_enable_xmt(mvi, i); mvs_94xx_phy_enable(mvi, i); @@ -219,7 +274,6 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi) */ cctl = mr32(MVS_CTL); cctl |= CCTL_ENDIAN_CMD; - cctl |= CCTL_ENDIAN_DATA; cctl &= ~CCTL_ENDIAN_OPEN; cctl |= CCTL_ENDIAN_RSP; mw32_f(MVS_CTL, cctl); @@ -233,10 +287,10 @@ static int __devinit mvs_94xx_init(struct mvs_info *mvi) * it will make count 0. */ tmp = 0; - if (MVS_SLOTS > 0x1ff) + if (MVS_CHIP_SLOT_SZ > 0x1ff) mw32(MVS_INT_COAL, 0x1ff|COAL_EN); else - mw32(MVS_INT_COAL, MVS_SLOTS|COAL_EN); + mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN); tmp = 0x10400; mw32(MVS_INT_COAL_TMOUT, tmp); @@ -424,9 +478,13 @@ static void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd) int i; struct scatterlist *sg; struct mvs_prd *buf_prd = prd; + struct mvs_prd_imt im_len; + *(u32 *)&im_len = 0; for_each_sg(scatter, sg, nr, i) { buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); - buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg)); + im_len.len = sg_dma_len(sg); + buf_prd->im_len = + cpu_to_le32(*(u32 *)&im_len); buf_prd++; } } @@ -449,7 +507,7 @@ static void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id, for (i = 0; i < 7; i++) { mvs_write_port_cfg_addr(mvi, port_id, CONFIG_ID_FRAME0 + i * 4); - id_frame[i] = mvs_read_port_cfg_data(mvi, port_id); + id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id)); } memcpy(id, id_frame, 28); } @@ -464,7 +522,7 @@ static void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id, for (i = 0; i < 7; i++) { mvs_write_port_cfg_addr(mvi, port_id, CONFIG_ATT_ID_FRAME0 + i * 4); - id_frame[i] = mvs_read_port_cfg_data(mvi, port_id); + id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id)); mv_dprintk("94xx phy %d atta frame %d %x.\n", port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]); } @@ -525,12 +583,40 @@ static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i, } +static void mvs_94xx_phy_work_around(struct mvs_info *mvi, int i) +{ + u32 tmp; + struct mvs_phy *phy = &mvi->phy[i]; + /* workaround for HW phy decoding error on 1.5g disk drive */ + mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6); + tmp = mvs_read_port_vsr_data(mvi, i); + if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> + PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) == + SAS_LINK_RATE_1_5_GBPS) + tmp &= ~PHY_MODE6_LATECLK; + else + tmp |= PHY_MODE6_LATECLK; + mvs_write_port_vsr_data(mvi, i, tmp); +} + void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, struct sas_phy_linkrates *rates) { - /* TODO */ + u32 lrmax = 0; + u32 tmp; + + tmp = mvs_read_phy_ctl(mvi, phy_id); + lrmax = (rates->maximum_linkrate - SAS_LINK_RATE_1_5_GBPS) << 12; + + if (lrmax) { + tmp &= ~(0x3 << 12); + tmp |= lrmax; + } + mvs_write_phy_ctl(mvi, phy_id, tmp); + mvs_94xx_phy_reset(mvi, phy_id, 1); } + #ifdef SUPPORT_TARGET static void mvs_91xx_enable_ssp_target(struct mvs_info *mvi, u32 phy_id) @@ -636,10 +722,14 @@ void mvs_94xx_fix_dma(dma_addr_t buf_dma, int buf_len, int from, void *prd) { int i; struct mvs_prd *buf_prd = prd; + struct mvs_prd_imt im_len; + *(u32 *)&im_len = 0; buf_prd += from; for (i = 0; i < MAX_SG_ENTRY - from; i++) { buf_prd->addr = cpu_to_le64(buf_dma); - buf_prd->im_len.len = cpu_to_le32(buf_len); + im_len.len = buf_len; + buf_prd->im_len = + cpu_to_le32(*(u32 *)&im_len); ++buf_prd; } } @@ -681,13 +771,13 @@ const struct mvs_dispatch mvs_94xx_dispatch = { mvs_94xx_detect_porttype, mvs_94xx_oob_done, mvs_94xx_fix_phy_info, - NULL, + mvs_94xx_phy_work_around, mvs_94xx_phy_set_link_rate, mvs_hw_max_link_rate, mvs_94xx_phy_disable, mvs_94xx_phy_enable, mvs_94xx_phy_reset, - NULL, + mvs_94xx_stp_reset, #ifdef SUPPORT_TARGET mvs_91xx_enable_ssp_target, mvs_91xx_disable_ssp_target, diff --git a/mvsas_tgt/mv_94xx.h b/mvsas_tgt/mv_94xx.h index 23ed9b164..32b6b8578 100644 --- a/mvsas_tgt/mv_94xx.h +++ b/mvsas_tgt/mv_94xx.h @@ -171,17 +171,24 @@ enum pci_interrupt_cause { #define MAX_SG_ENTRY 255 struct mvs_prd_imt { +#ifndef __BIG_ENDIAN __le32 len:22; u8 _r_a:2; u8 misc_ctl:4; u8 inter_sel:4; +#else + u32 inter_sel:4; + u32 misc_ctl:4; + u32 _r_a:2; + u32 len:22; +#endif }; struct mvs_prd { /* 64-bit buffer address */ __le64 addr; /* 22-bit length */ - struct mvs_prd_imt im_len; + __le32 im_len; } __attribute__ ((packed)); #define SPI_CTRL_REG_94XX 0xc800 diff --git a/mvsas_tgt/mv_chips.h b/mvsas_tgt/mv_chips.h index a67e1c417..2e7dd1b0f 100644 --- a/mvsas_tgt/mv_chips.h +++ b/mvsas_tgt/mv_chips.h @@ -190,11 +190,12 @@ static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi) tmp &= 0x0000ffff; tmp |= 0x00fa0000; mvs_cw32(mvi, CMD_PHY_MODE_21, tmp); - +#if 0 tmp = mvs_cr32(mvi, CMD_PHY_TIMER); tmp &= 0x1fffffff; tmp |= (2U << 29); /* 8 ms retry */ mvs_cw32(mvi, CMD_PHY_TIMER, tmp); +#endif } static inline void mvs_int_sata(struct mvs_info *mvi) diff --git a/mvsas_tgt/mv_defs.h b/mvsas_tgt/mv_defs.h index e5d054d23..3d4bf8813 100644 --- a/mvsas_tgt/mv_defs.h +++ b/mvsas_tgt/mv_defs.h @@ -36,7 +36,6 @@ enum chip_flavors { /* driver compile-time configuration */ enum driver_configuration { - MVS_SLOTS = 512, /* command slots */ MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */ MVS_RX_RING_SZ = 1024, /* RX ring size (12-bit) */ /* software requires power-of-2 @@ -50,10 +49,9 @@ enum driver_configuration { MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */ MVS_OAF_SZ = 64, /* Open address frame buffer size */ #ifdef SUPPORT_TARGET - MVS_TARGET_QUEUE = 32, + MVS_TARGET_QUEUE = 64, #endif - MVS_QUEUE_SIZE = 32, /* Support Queue depth */ - MVS_CAN_QUEUE = MVS_SLOTS - 2, /* SCSI Queue depth */ + MVS_QUEUE_SIZE = 64, /* Support Queue depth */ MVS_SOC_CAN_QUEUE = MVS_SOC_SLOTS - 2, #ifdef SUPPORT_TARGET MVS_MAX_STP_FRAME = 0x10, @@ -405,6 +403,7 @@ enum mvs_event_flags { PHY_PLUG_EVENT = (3U), PHY_PLUG_IN = (1U << 0), /* phy plug in */ PHY_PLUG_OUT = (1U << 1), /* phy plug out */ + EXP_BRCT_CHG = (1U << 2), /* broadcast change */ }; enum mvs_port_type { diff --git a/mvsas_tgt/mv_init.c b/mvsas_tgt/mv_init.c index e9724f175..da2660622 100644 --- a/mvsas_tgt/mv_init.c +++ b/mvsas_tgt/mv_init.c @@ -33,8 +33,8 @@ static const struct mvs_chip_info mvs_chips[] = { [chip_6320] = { 1, 2, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, [chip_6440] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, [chip_6485] = { 1, 8, 0x800, 33, 32, 6, 10, &mvs_64xx_dispatch, }, - [chip_9180] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, - [chip_9480] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, + [chip_9180] = { 2, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, }, + [chip_9480] = { 2, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, }, }; #ifdef SUPPORT_TARGET @@ -90,14 +90,13 @@ static struct sas_domain_function_template mvs_transport_ops = { .lldd_abort_task = mvs_abort_task, .lldd_abort_task_set = mvs_abort_task_set, .lldd_clear_aca = mvs_clear_aca, - .lldd_clear_task_set = mvs_clear_task_set, + .lldd_clear_task_set = mvs_clear_task_set, .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, .lldd_lu_reset = mvs_lu_reset, .lldd_query_task = mvs_query_task, .lldd_port_formed = mvs_port_formed, .lldd_port_deformed = mvs_port_deformed, - }; static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) @@ -106,6 +105,7 @@ static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) struct asd_sas_phy *sas_phy = &phy->sas_phy; phy->mvi = mvi; + phy->port = NULL; init_timer(&phy->timer); sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; sas_phy->class = SAS; @@ -135,7 +135,7 @@ static void mvs_free(struct mvs_info *mvi) if (mvi->flags & MVF_FLAG_SOC) slot_nr = MVS_SOC_SLOTS; else - slot_nr = MVS_SLOTS; + slot_nr = MVS_CHIP_SLOT_SZ; for (i = 0; i < mvi->tags_num; i++) { struct mvs_slot_info *slot = &mvi->slot_info[i]; @@ -170,6 +170,7 @@ static void mvs_free(struct mvs_info *mvi) scsi_host_put(mvi->shost); list_for_each_entry(mwq, &mvi->wq_list, entry) cancel_delayed_work(&mwq->work_q); + kfree(mvi->tags); kfree(mvi); } @@ -230,12 +231,16 @@ static irqreturn_t mvs_interrupt(int irq, void *opaque) static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) { - int i, slot_nr; + int i = 0, j = 0, slot_nr; + unsigned long buf_size; + void *buf; + dma_addr_t buf_dma; + struct mvs_slot_info *slot = 0; if (mvi->flags & MVF_FLAG_SOC) slot_nr = MVS_SOC_SLOTS; else - slot_nr = MVS_SLOTS; + slot_nr = MVS_CHIP_SLOT_SZ; spin_lock_init(&mvi->lock); for (i = 0; i < mvi->chip->n_phy; i++) { @@ -289,17 +294,26 @@ static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) if (!mvi->bulk_buffer) goto err_out; #endif - for (i = 0; i < slot_nr; i++) { - struct mvs_slot_info *slot = &mvi->slot_info[i]; - - slot->buf = dma_alloc_coherent(mvi->dev, MVS_SLOT_BUF_SZ, - &slot->buf_dma, GFP_KERNEL); - if (!slot->buf) { + i = 0; + while (i < slot_nr) { + buf_size = PAGE_SIZE > MVS_SLOT_BUF_SZ ? + PAGE_SIZE : MVS_SLOT_BUF_SZ; + buf = dma_alloc_coherent(mvi->dev, buf_size, + &buf_dma, GFP_KERNEL); + if (!buf) { printk(KERN_DEBUG"failed to allocate slot->buf.\n"); goto err_out; } - memset(slot->buf, 0, MVS_SLOT_BUF_SZ); - ++mvi->tags_num; + j = 0; + do { + slot = &mvi->slot_info[i + j]; + slot->buf = buf + MVS_SLOT_BUF_SZ * j; + slot->buf_dma = buf_dma + MVS_SLOT_BUF_SZ * j; + memset(slot->buf, 0, MVS_SLOT_BUF_SZ); + ++mvi->tags_num; + j++; + } while (j < PAGE_SIZE/MVS_SLOT_BUF_SZ); + i += j; } /* Initialize tags */ mvs_tag_init(mvi); @@ -367,11 +381,12 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev, const struct pci_device_id *ent, struct Scsi_Host *shost, unsigned int id) { - struct mvs_info *mvi; + struct mvs_info *mvi = NULL; struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - mvi = kzalloc(sizeof(*mvi) + MVS_SLOTS * sizeof(struct mvs_slot_info), - GFP_KERNEL); + mvi = kzalloc(sizeof(*mvi) + + (1L << mvs_chips[ent->driver_data].slot_width) + * sizeof(struct mvs_slot_info), GFP_KERNEL); if (!mvi) return NULL; @@ -388,6 +403,10 @@ static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev, mvi->id = id; mvi->sas = sha; mvi->shost = shost; + mvi->tags = kzalloc(MVS_CHIP_SLOT_SZ>>3, GFP_KERNEL); + if (!mvi->tags) + goto err_out; + #ifdef MVS_USE_TASKLET tasklet_init(&mv_tasklet, mvs_tasklet, (unsigned long)sha); #endif @@ -462,7 +481,7 @@ static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost, ((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr; shost->transportt = mvs_stt; - shost->max_id = 128; + shost->max_id = MVS_MAX_DEVICES; shost->max_lun = ~0; shost->max_channel = 1; shost->max_cmd_len = 16; @@ -505,12 +524,12 @@ static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost, if (mvi->flags & MVF_FLAG_SOC) can_queue = MVS_SOC_CAN_QUEUE; else - can_queue = MVS_CAN_QUEUE; + can_queue = MVS_CHIP_SLOT_SZ; sha->lldd_queue_size = can_queue; shost->sg_tablesize = MVS_MAX_SG; shost->can_queue = can_queue; - mvi->shost->cmd_per_lun = MVS_SLOTS/sha->num_phys; + mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE; sha->core.shost = mvi->shost; } @@ -519,7 +538,9 @@ static void mvs_init_sas_add(struct mvs_info *mvi) { u8 i; for (i = 0; i < mvi->chip->n_phy; i++) { - mvi->phy[i].dev_sas_addr = 0x5005043011ab0000ULL; + mvi->phy[i].dev_sas_addr = 0x5005043011ab0000ULL; + if (mvi->id == 1) + mvi->phy[i].dev_sas_addr = 0x5005043011ab0001ULL; mvi->phy[i].dev_sas_addr = cpu_to_be64((u64)(*(u64 *)&mvi->phy[i].dev_sas_addr)); } @@ -713,7 +734,15 @@ static struct pci_device_id __devinitdata mvs_pci_table[] = { { PCI_VDEVICE(MARVELL, 0x6485), chip_6485 }, { PCI_VDEVICE(MARVELL, 0x9480), chip_9480 }, { PCI_VDEVICE(MARVELL, 0x9180), chip_9180 }, - + { + .vendor = 0x1b4b, + .device = 0x9480, + .subvendor = PCI_ANY_ID, + .subdevice = 0x9480, + .class = 0, + .class_mask = 0, + .driver_data = chip_9480, + }, { } /* terminate list */ }; @@ -947,11 +976,18 @@ struct device_attribute *mvst_host_attrs[] = { #endif /* #ifdef SUPPORT_TARGET */ - +/* task handler */ +struct task_struct *mvs_th; static int __init mvs_init(void) { int rc; - +#ifdef SUPPORT_EXP_LB + mvs_th = kthread_run(mvs_ex_task_scheduler, NULL, "mvs_work"); + if (mvs_th == ERR_PTR(-ENOMEM)) { + mv_printk("mvsas kernel thread creation failed\n"); + return -ENOMEM; + } +#endif mvs_stt = sas_domain_attach_transport(&mvs_transport_ops); if (!mvs_stt) return -ENOMEM; @@ -972,6 +1008,10 @@ static void __exit mvs_exit(void) { pci_unregister_driver(&mvs_pci_driver); sas_release_transport(mvs_stt); +#ifdef SUPPORT_EXP_LB + if (mvs_th != NULL) + kthread_stop(mvs_th); +#endif } module_init(mvs_init); diff --git a/mvsas_tgt/mv_sas.c b/mvsas_tgt/mv_sas.c index 503c95fda..6dc041aaa 100644 --- a/mvsas_tgt/mv_sas.c +++ b/mvsas_tgt/mv_sas.c @@ -32,7 +32,7 @@ static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) { if (task->lldd_task) { struct mvs_slot_info *slot; - slot = (struct mvs_slot_info *) task->lldd_task; + slot = task->lldd_task; *tag = slot->slot_tag; return 1; } @@ -41,7 +41,7 @@ static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) void mvs_tag_clear(struct mvs_info *mvi, u32 tag) { - void *bitmap = (void *) &mvi->tags; + void *bitmap = mvi->tags; clear_bit(tag, bitmap); } @@ -52,14 +52,14 @@ void mvs_tag_free(struct mvs_info *mvi, u32 tag) void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) { - void *bitmap = (void *) &mvi->tags; + void *bitmap = mvi->tags; set_bit(tag, bitmap); } inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) { unsigned int index, tag; - void *bitmap = (void *) &mvi->tags; + void *bitmap = mvi->tags; index = find_first_zero_bit(bitmap, mvi->tags_num); tag = index; @@ -229,7 +229,7 @@ struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev) int mvs_find_dev_phyno(struct domain_device *dev, int *phyno) { unsigned long i = 0, j = 0, n = 0, num = 0; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_info *mvi = mvi_dev->mvi_info; struct sas_ha_struct *sha = dev->port->ha; @@ -263,7 +263,7 @@ static inline void mvs_free_reg_set(struct mvs_info *mvi, mv_printk("device has been free.\n"); return; } - if (dev->runing_req != 0) + if (dev->running_req != 0) return; if (dev->taskfileset == MVS_ID_NOT_MAPPED) return; @@ -419,7 +419,9 @@ int mvs_slave_configure(struct scsi_device *sdev) adev->flags |= ATA_DFLAG_NCQ_OFF; scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, 1); #endif - } + } else + sas_change_queue_depth(sdev, MVS_QUEUE_SIZE); + return 0; } @@ -596,8 +598,7 @@ static int mvs_task_prep_ata(struct mvs_info *mvi, { struct sas_task *task = tei->task; struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = - (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_cmd_hdr *hdr = tei->hdr; struct asd_sas_port *sas_port = dev->port; struct mvs_slot_info *slot; @@ -740,8 +741,7 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi, struct mvs_cmd_hdr *hdr = tei->hdr; struct mvs_port *port = tei->port; struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = - (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = dev->lldd_dev; struct asd_sas_port *sas_port = dev->port; struct mvs_slot_info *slot; void *buf_prd; @@ -833,17 +833,17 @@ static int mvs_task_prep_ssp(struct mvs_info *mvi, /* fill in SSP frame header (Command Table.SSP frame header) */ ssp_hdr = (struct ssp_frame_hdr *)buf_cmd; - if (is_tmf) - ssp_hdr->frame_type = SSP_TASK; - else - ssp_hdr->frame_type = SSP_COMMAND; - memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); memcpy(ssp_hdr->hashed_src_addr, dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); ssp_hdr->tag = cpu_to_be16(tag); + if (is_tmf) + ssp_hdr->frame_type = SSP_TASK; + else + ssp_hdr->frame_type = SSP_COMMAND; + /* fill in IU for TASK and Command Frame */ buf_cmd += sizeof(*ssp_hdr); memcpy(buf_cmd, &task->ssp_task.LUN, 8); @@ -877,7 +877,7 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, struct mvs_tmf_task *tmf) { struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_info *mvi = mvi_dev->mvi_info; struct mvs_task_exec_info tei; struct sas_task *t = task; @@ -904,7 +904,7 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, spin_lock_irqsave(&mvi->lock, flags); do { dev = t->dev; - mvi_dev = (struct mvs_device *)dev->lldd_dev; + mvi_dev = dev->lldd_dev; if (DEV_IS_GONE(mvi_dev)) { if (mvi_dev) mv_dprintk("device %d not ready.\n", @@ -925,7 +925,7 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, if (!tei.port->port_attached) { if (sas_protocol_ata(t->task_proto)) { mv_dprintk("port %d does not" - "attached device.\n", dev->port->id); + " attach device.\n", dev->port->id); rc = SAS_PHY_DOWN; goto out_done; } else { @@ -995,7 +995,7 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, } slot->task = t; slot->port = tei.port; - t->lldd_task = (void *) slot; + t->lldd_task = slot; list_add_tail(&slot->entry, &tei.port->list); /* TODO: select normal or high priority */ spin_lock(&t->task_state_lock); @@ -1003,7 +1003,7 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, spin_unlock(&t->task_state_lock); mvs_hba_memory_dump(mvi, tag, t->task_proto); - mvi_dev->runing_req++; + mvi_dev->running_req++; ++pass; mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); if (n > 1) @@ -1143,7 +1143,7 @@ static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3); s[3] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); - + MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2); s[2] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); @@ -1157,7 +1157,7 @@ static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01)) s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10); - return (void *)s; + return s; } static u32 mvs_is_sig_fis_received(u32 irq_status) @@ -1194,7 +1194,7 @@ void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st) sas_phy->oob_mode = SATA_OOB_MODE; phy->frame_rcvd_size = sizeof(struct dev_to_host_fis); - mvs_get_d2h_reg(mvi, i, (void *)id); + mvs_get_d2h_reg(mvi, i, id); } else { u32 tmp; dev_printk(KERN_DEBUG, mvi->dev, @@ -1289,7 +1289,7 @@ static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock) static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock) { struct domain_device *dev; - struct mvs_phy *phy = (struct mvs_phy *)sas_phy->lldd_phy; + struct mvs_phy *phy = sas_phy->lldd_phy; struct mvs_info *mvi = phy->mvi; struct asd_sas_port *port = sas_phy->port; int phy_no = 0; @@ -1358,7 +1358,7 @@ int mvs_dev_found_notify(struct domain_device *dev, int lock) res = -1; goto found_out; } - dev->lldd_dev = (void *)mvi_device; + dev->lldd_dev = mvi_device; mvi_device->dev_type = dev->dev_type; mvi_device->mvi_info = mvi; if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { @@ -1394,15 +1394,13 @@ int mvs_dev_found(struct domain_device *dev) return mvs_dev_found_notify(dev, 1); } -void mvs_dev_gone_notify(struct domain_device *dev, int lock) +void mvs_dev_gone_notify(struct domain_device *dev) { unsigned long flags = 0; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_info *mvi = mvi_dev->mvi_info; - if (lock) - spin_lock_irqsave(&mvi->lock, flags); - + spin_lock_irqsave(&mvi->lock, flags); if (mvi_dev) { mv_dprintk("found dev[%d:%x] is gone.\n", mvi_dev->device_id, mvi_dev->dev_type); @@ -1413,15 +1411,13 @@ void mvs_dev_gone_notify(struct domain_device *dev, int lock) mv_dprintk("found dev has gone.\n"); } dev->lldd_dev = NULL; - - if (lock) - spin_unlock_irqrestore(&mvi->lock, flags); + spin_unlock_irqrestore(&mvi->lock, flags); } void mvs_dev_gone(struct domain_device *dev) { - mvs_dev_gone_notify(dev, 1); + mvs_dev_gone_notify(dev); } static struct sas_task *mvs_alloc_task(void) @@ -1574,7 +1570,7 @@ int mvs_lu_reset(struct domain_device *dev, u8 *lun) unsigned long flags; int rc = TMF_RESP_FUNC_FAILED; struct mvs_tmf_task tmf_task; - struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_info *mvi = mvi_dev->mvi_info; tmf_task.tmf = TMF_LU_RESET; @@ -1595,7 +1591,7 @@ int mvs_I_T_nexus_reset(struct domain_device *dev) { unsigned long flags; int rc = TMF_RESP_FUNC_FAILED; - struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_info *mvi = mvi_dev->mvi_info; if (mvi_dev->dev_status != MVS_DEV_EH) @@ -1623,7 +1619,7 @@ int mvs_query_task(struct sas_task *task) if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task; struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_info *mvi = mvi_dev->mvi_info; int_to_scsilun(cmnd->device->lun, &lun); @@ -1656,19 +1652,16 @@ int mvs_abort_task(struct sas_task *task) struct scsi_lun lun; struct mvs_tmf_task tmf_task; struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; + struct mvs_device *mvi_dev = dev->lldd_dev; struct mvs_info *mvi = mvi_dev->mvi_info; int rc = TMF_RESP_FUNC_FAILED; - unsigned long flags; u32 tag; - spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); rc = TMF_RESP_FUNC_COMPLETE; goto out; } - spin_unlock_irqrestore(&task->task_state_lock, flags); + if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task; @@ -1679,7 +1672,6 @@ int mvs_abort_task(struct sas_task *task) rc = TMF_RESP_FUNC_FAILED; return rc; } - tmf_task.tmf = TMF_ABORT_TASK; tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); @@ -1689,11 +1681,13 @@ int mvs_abort_task(struct sas_task *task) if (rc == TMF_RESP_FUNC_COMPLETE) { u32 slot_no; struct mvs_slot_info *slot; - + unsigned long flags; if (task->lldd_task) { - slot = (struct mvs_slot_info *)task->lldd_task; + slot = task->lldd_task; slot_no = (u32) (slot - mvi->slot_info); + spin_lock_irqsave(&mvi->lock, flags); mvs_slot_complete(mvi, slot_no, 1); + spin_unlock_irqrestore(&mvi->lock, flags); } } } else if (task->task_proto & SAS_PROTOCOL_SATA || @@ -1744,12 +1738,11 @@ int mvs_clear_task_set(struct domain_device *dev, u8 *lun) static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, u32 slot_idx, int err) { - struct mvs_device *mvi_dev = (struct mvs_device *)task->dev->lldd_dev; + struct mvs_device *mvi_dev = task->dev->lldd_dev; struct task_status_struct *tstat = &task->task_status; struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; int stat = SAM_GOOD; - resp->frame_len = sizeof(struct dev_to_host_fis); memcpy(&resp->ending_fis[0], SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset), @@ -1787,13 +1780,9 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, case SAS_PROTOCOL_STP: case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { - if (err_dw0 == 0x80400002) - mv_printk("find reserved error, why?\n"); - task->ata_task.use_ncq = 0; stat = SAS_PROTO_RESPONSE; mvs_sata_done(mvi, task, slot_idx, 1); - } break; default: @@ -1803,6 +1792,7 @@ static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, return stat; } + int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) { u32 slot_idx = rx_desc & RXQ_SLOT_MASK; @@ -1839,7 +1829,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) if (unlikely(aborted)) { tstat->stat = SAS_ABORTED_TASK; if (mvi_dev) - mvi_dev->runing_req--; + mvi_dev->running_req--; if (sas_protocol_ata(task->task_proto)) mvs_free_reg_set(mvi, mvi_dev); @@ -1864,6 +1854,8 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) /* error info record present */ if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) { + if (task->task_proto & (SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP)) + mvs_sata_done(mvi, task, slot_idx, 0); tstat->stat = mvs_slot_err(mvi, task, slot_idx); goto out; } @@ -1885,14 +1877,17 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) break; case SAS_PROTOCOL_SMP: { - struct scatterlist *sg_resp = &task->smp_task.smp_resp; - tstat->stat = SAM_GOOD; - to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); - memcpy(to + sg_resp->offset, - slot->response + sizeof(struct mvs_err_info), - sg_dma_len(sg_resp)); - kunmap_atomic(to, KM_IRQ0); - break; + struct scatterlist *sg_resp = &task->smp_task.smp_resp; + tstat->stat = SAM_GOOD; + to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); + memcpy(to + sg_resp->offset, + slot->response + sizeof(struct mvs_err_info), + sg_dma_len(sg_resp)); + memcpy(to + sg_resp->offset, + slot->response + sizeof(struct mvs_err_info), + sg_resp->length); + kunmap_atomic(to, KM_IRQ0); + break; } case SAS_PROTOCOL_SATA: @@ -1909,7 +1904,7 @@ int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) out: if (mvi_dev) { - mvi_dev->runing_req--; + mvi_dev->running_req--; if (sas_protocol_ata(task->task_proto)) mvs_free_reg_set(mvi, mvi_dev); } @@ -1983,15 +1978,14 @@ static void mvs_work_queue(void *arg) #endif struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q); struct mvs_info *mvi = mwq->mvi; + u32 phy_no = (unsigned long) mwq->data; + struct sas_ha_struct *sas_ha = mvi->sas; + struct mvs_phy *phy = &mvi->phy[phy_no]; + struct asd_sas_phy *sas_phy = &phy->sas_phy; unsigned long flags; spin_lock_irqsave(&mvi->lock, flags); if (mwq->handler & PHY_PLUG_EVENT) { - u32 phy_no = (unsigned long) mwq->data; - struct sas_ha_struct *sas_ha = mvi->sas; - struct mvs_phy *phy = &mvi->phy[phy_no]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - if (phy->phy_event & PHY_PLUG_OUT) { u32 tmp; struct sas_identify_frame *id; @@ -2012,6 +2006,11 @@ static void mvs_work_queue(void *arg) mv_dprintk("phy%d Attached Device\n", phy_no); } } + } else if (mwq->handler & EXP_BRCT_CHG) { + phy->phy_event &= ~EXP_BRCT_CHG; + sas_ha->notify_port_event(sas_phy, + PORTE_BROADCAST_RCVD); + mv_dprintk("phy%d Got Broadcast Change\n", phy_no); } list_del(&mwq->entry); spin_unlock_irqrestore(&mvi->lock, flags); @@ -2030,7 +2029,7 @@ static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler) mwq->handler = handler; MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq); list_add_tail(&mwq->entry, &mvi->wq_list); - schedule_delayed_work(&mwq->work_q, HZ * 2); + schedule_delayed_work(&mwq->work_q, HZ * DISK_FLASH_HOLD_TIME); } else ret = -ENOMEM; @@ -2062,7 +2061,6 @@ static void mvs_sig_remove_timer(struct mvs_phy *phy) void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) { u32 tmp; - struct sas_ha_struct *sas_ha = mvi->sas; struct mvs_phy *phy = &mvi->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; @@ -2078,21 +2076,21 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) */ if (phy->irq_status & PHYEV_DCDR_ERR) { - mvs_do_release_task(mvi, phy_no, NULL); mv_dprintk("port %d STP decoding error.\n", - phy_no+mvi->id*mvi->chip->n_phy); + phy_no + mvi->id*mvi->chip->n_phy); } if (phy->irq_status & PHYEV_POOF) { #ifdef SUPPORT_TARGET /*if initiator plug out*/ - mv_dprintk("port %d attr is %x\n", phy_no, + mv_dprintk("port %d attr is %x\n", + phy_no + mvi->id*mvi->chip->n_phy, mvi->tgt_port[phy_no].port_attr); if (mvi->tgt_port[phy_no].port_attr == MVST_TGT_PORT || mvi->tgt_port[phy_no].port_attr == MVST_INIT_TGT_PORT) { + struct sas_ha_struct *sas_ha = mvi->sas; phy->phy_event |= PHY_PLUG_OUT; - mvs_do_release_task(mvi, phy_no, NULL); sas_phy_disconnected(sas_phy); mvs_phy_disconnected(phy); mv_dprintk("notify plug out on phy[%d]\n", phy_no + @@ -2164,11 +2162,13 @@ void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) phy_no + mvi->id*mvi->chip->n_phy); } } else if (phy->irq_status & PHYEV_BROAD_CH) { - mv_dprintk("port %d broadcast change.\n", - phy_no + mvi->id*mvi->chip->n_phy); - /* exception for Samsung disk drive*/ - mdelay(1000); - sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); + mv_dprintk("port %d broadcast change.\n", + phy_no + mvi->id*mvi->chip->n_phy); + #ifdef SUPPORT_EXP_LB + mvi->exp_brct = 1; + #endif + mvs_handle_event(mvi, (void *)(unsigned long)phy_no, + EXP_BRCT_CHG); } MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status); } diff --git a/mvsas_tgt/mv_sas.h b/mvsas_tgt/mv_sas.h index c09b47825..c5ff418a7 100644 --- a/mvsas_tgt/mv_sas.h +++ b/mvsas_tgt/mv_sas.h @@ -47,10 +47,11 @@ #endif #define DRV_NAME "mvsas" -#define DRV_VERSION "0.8.3" +#define DRV_VERSION "0.8.4" #define _MV_DUMP 0 #define MVS_ID_NOT_MAPPED 0x7f /* #define DISABLE_HOTPLUG_DMA_FIX */ +#define DISK_FLASH_HOLD_TIME 10 #define WIDE_PORT_MAX_PHY 4 #define MV_DISABLE_NCQ 0 #define mv_printk(fmt, arg ...) \ @@ -259,7 +260,7 @@ struct mvs_device { struct domain_device *sas_device; u32 attached_phy; u32 device_id; - u32 runing_req; + u32 running_req; u8 taskfileset; u8 dev_status; u16 reserved; @@ -343,7 +344,7 @@ struct mvs_info { const struct mvs_chip_info *chip; int tags_num; - DECLARE_BITMAP(tags, MVS_SLOTS); + unsigned long *tags; /* further per-slot information */ struct mvs_phy phy[MVS_MAX_PHYS]; struct mvs_port port[MVS_MAX_PHYS]; diff --git a/mvsas_tgt/mv_spi.c b/mvsas_tgt/mv_spi.c index 4057cc4c4..de4563cd8 100644 --- a/mvsas_tgt/mv_spi.c +++ b/mvsas_tgt/mv_spi.c @@ -514,6 +514,8 @@ u8 mvs_spi_init(struct mvs_info *mvi) if (!mvui_init_param(mvi, &hba_info_para)) { for (i = 0; i < mvi->chip->n_phy; i++) { sas_addr = 0x5005043011ab0000ULL; + if (mvi->id == 1) + sas_addr = 0x5005043011ab0001ULL; mvi->phy[i].dev_sas_addr = cpu_to_be64((u64)(*(u64 *)&sas_addr)); } diff --git a/mvsas_tgt/mv_tgt.c b/mvsas_tgt/mv_tgt.c index cf16ac408..3f724b8f4 100644 --- a/mvsas_tgt/mv_tgt.c +++ b/mvsas_tgt/mv_tgt.c @@ -379,7 +379,6 @@ mvst_get_slot(struct mvs_info *mvi, struct mvst_port *tgt_port) slot->tx = mvi->tx_prod; list_add_tail(&slot->entry, &slot->slot_tgt_port->slot_list); return slot; - } static int mvst_prep_resp_frame(struct mvst_prm *prm, @@ -760,7 +759,7 @@ static int mvst_xmit_response(struct scst_cmd *scst_cmd) TRACE_ENTRY(); - TRACE(TRACE_SCSI, "xmit_respons scmd[0x%p] tag=%ld, sg_cnt=%d", + TRACE(TRACE_SCSI, "xmit_respons scmd[0x%p] tag=%lld, sg_cnt=%d", scst_cmd, scst_cmd_get_tag(scst_cmd), scst_cmd->sg_cnt); #ifdef DEBUG_WORK_IN_THREAD @@ -774,9 +773,9 @@ static int mvst_xmit_response(struct scst_cmd *scst_cmd) scst_sess_get_tgt_priv(scst_cmd_get_session(scst_cmd)); if (unlikely(scst_cmd_aborted(scst_cmd))) { - TRACE(TRACE_MGMT_MINOR, "mvst tgt(%ld): terminating exchange " - "for aborted scst_cmd=%p (tag=%ld)", - mvi->instance, scst_cmd, scst_cmd_get_tag(scst_cmd)); + TRACE(TRACE_MGMT_MINOR, "mvst tgt: terminating exchange " + "for aborted scst_cmd=%p (tag=%lld)", + scst_cmd, scst_cmd_get_tag(scst_cmd)); scst_set_delivery_status(scst_cmd, SCST_CMD_DELIVERY_ABORTED); @@ -1187,7 +1186,6 @@ static void mvst_do_cmd_completion(struct mvs_info *mvi, (struct open_address_frame *)slot->open_frame; struct ssp_frame_header *ssp_hdr; struct mvst_sess *sess; - TRACE_BUFFER("SSP Header", ssp_hdr, sizeof(*ssp_hdr)); TRACE_BUFFER("SSP open_frame", open_frame, sizeof(*open_frame)); dest_sas_addr = (open_frame->dest_sas_addr); sess = mvst_find_sess_by_lid(mvi->tgt, @@ -1373,7 +1371,7 @@ static int mvst_do_send_cmd_to_scst(struct mvs_info *mvi, struct mvst_cmd *cmd) context = SCST_CONTEXT_TASKLET; #endif TRACE_DBG("Context %x", context); - TRACE(TRACE_SCSI, "START Command (tag %ld)", + TRACE(TRACE_SCSI, "START Command (tag %lld)", scst_cmd_get_tag(cmd->scst_cmd)); scst_cmd_init_done(cmd->scst_cmd, context); out: @@ -1502,7 +1500,7 @@ int mvst_build_cmd(struct mvs_info *mvi, if (mvi->tgt->tgt_shutdown) { TRACE_DBG("New command while device %p is shutting " - "down", tgt); + "down", tgt_port); res = -EFAULT; goto out; } @@ -2288,8 +2286,8 @@ static void mvst_host_action(struct mvs_info *mvi, (mvi->tgt_port[target_port].sas_addr), mvi->tgt_port[target_port].wide_port_phymap, target_port); - if (target_port * (MVS_SLOTS/mvi->chip->n_phy) - > MVS_CAN_QUEUE) { + if (target_port * (MVS_CHIP_SLOT_SZ/mvi->chip->n_phy) + > MVS_CHIP_SLOT_SZ) { mv_dprintk("Warning: No sufficient slots" "for target port[%d].\n", target_port); break; @@ -2504,8 +2502,7 @@ mvst_start_sas_target(struct mvs_info *mvi, u8 id) goto err_out_tag; ++pass; mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); - } while (++slot_id < MVS_SLOTS/mvi->chip->n_phy); - + } while (++slot_id < MVS_TARGET_QUEUE); rc = 0; goto out_done;