mv_sas.c revision 477f6d190bdebc9a3ec99e4bb396b981f747bf19
1b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik/* 220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * Marvell 88SE64xx/88SE94xx main function 320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * 420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * Copyright 2007 Red Hat, Inc. 520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * Copyright 2008 Marvell. <kewei@marvell.com> 60b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu * Copyright 2009-2011 Marvell. <yuxiangl@marvell.com> 720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * 820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * This file is licensed under GPLv2. 920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * 1020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * This program is free software; you can redistribute it and/or 1120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * modify it under the terms of the GNU General Public License as 1220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * published by the Free Software Foundation; version 2 of the 1320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * License. 1420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * 1520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * This program is distributed in the hope that it will be useful, 1620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * but WITHOUT ANY WARRANTY; without even the implied warranty of 1720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * General Public License for more details. 1920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * 2020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * You should have received a copy of the GNU General Public License 2120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * along with this program; if not, write to the Free Software 2220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 2320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * USA 2420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan*/ 25b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 26dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik#include "mv_sas.h" 27b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 28dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) 29dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 30dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (task->lldd_task) { 31dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_slot_info *slot; 32f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan slot = task->lldd_task; 3320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *tag = slot->slot_tag; 34dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 1; 35dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 36dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 37dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 388f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 3920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_tag_clear(struct mvs_info *mvi, u32 tag) 40dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 41b89e8f539ff8bcf2a1464578fa91cb96cc433fc3Xiangliang Yu void *bitmap = mvi->tags; 42dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik clear_bit(tag, bitmap); 43dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 4520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_tag_free(struct mvs_info *mvi, u32 tag) 46dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 47dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_clear(mvi, tag); 48dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 5020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_tag_set(struct mvs_info *mvi, unsigned int tag) 51dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 52b89e8f539ff8bcf2a1464578fa91cb96cc433fc3Xiangliang Yu void *bitmap = mvi->tags; 53dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik set_bit(tag, bitmap); 54dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 5620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yaninline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) 57dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 58dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik unsigned int index, tag; 59b89e8f539ff8bcf2a1464578fa91cb96cc433fc3Xiangliang Yu void *bitmap = mvi->tags; 60b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan index = find_first_zero_bit(bitmap, mvi->tags_num); 62dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik tag = index; 6320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (tag >= mvi->tags_num) 64dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return -SAS_QUEUE_FULL; 65dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_set(mvi, tag); 66dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *tag_out = tag; 67dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 68dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 69b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 70dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_tag_init(struct mvs_info *mvi) 71dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 72dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int i; 7320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan for (i = 0; i < mvi->tags_num; ++i) 74dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_clear(mvi, i); 75dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 76b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 7720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstruct mvs_info *mvs_find_dev_mvi(struct domain_device *dev) 7820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 7920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned long i = 0, j = 0, hi = 0; 8020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_ha_struct *sha = dev->port->ha; 8120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_info *mvi = NULL; 8220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct asd_sas_phy *phy; 8320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 8420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan while (sha->sas_port[i]) { 8520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (sha->sas_port[i] == dev->port) { 8620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy = container_of(sha->sas_port[i]->phy_list.next, 8720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct asd_sas_phy, port_phy_el); 8820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan j = 0; 8920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan while (sha->sas_phy[j]) { 9020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (sha->sas_phy[j] == phy) 9120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 9220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan j++; 9320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 9420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 9520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 9620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i++; 9720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 9820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan hi = j/((struct mvs_prv_info *)sha->lldd_ha)->n_phy; 9920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi]; 1008f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 10120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return mvi; 1028f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 10320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 1048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 10520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_find_dev_phyno(struct domain_device *dev, int *phyno) 10620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 10720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned long i = 0, j = 0, n = 0, num = 0; 1089870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; 1099870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan struct mvs_info *mvi = mvi_dev->mvi_info; 11020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_ha_struct *sha = dev->port->ha; 11120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 11220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan while (sha->sas_port[i]) { 11320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (sha->sas_port[i] == dev->port) { 11420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct asd_sas_phy *phy; 11520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan list_for_each_entry(phy, 11620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan &sha->sas_port[i]->phy_list, port_phy_el) { 11720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan j = 0; 11820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan while (sha->sas_phy[j]) { 11920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (sha->sas_phy[j] == phy) 12020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 12120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan j++; 12220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 12320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phyno[n] = (j >= mvi->chip->n_phy) ? 12420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan (j - mvi->chip->n_phy) : j; 12520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan num++; 12620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan n++; 127dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 128dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 129dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 13020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i++; 13120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 13220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return num; 13320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 13420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 135534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yustruct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, 136534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu u8 reg_set) 137534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu{ 138534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu u32 dev_no; 139534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu for (dev_no = 0; dev_no < MVS_MAX_DEVICES; dev_no++) { 140534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu if (mvi->devices[dev_no].taskfileset == MVS_ID_NOT_MAPPED) 141534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu continue; 142534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu 143534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu if (mvi->devices[dev_no].taskfileset == reg_set) 144534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu return &mvi->devices[dev_no]; 145534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu } 146534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu return NULL; 147534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu} 148534ff10104427ccad071ef87ae7017d47d08e50bXiangliang Yu 14920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic inline void mvs_free_reg_set(struct mvs_info *mvi, 15020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_device *dev) 15120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 15220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!dev) { 15320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("device has been free.\n"); 15420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return; 15520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 15620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (dev->taskfileset == MVS_ID_NOT_MAPPED) 15720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return; 15820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset); 15920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 16020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 16120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic inline u8 mvs_assign_reg_set(struct mvs_info *mvi, 16220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_device *dev) 16320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 16420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (dev->taskfileset != MVS_ID_NOT_MAPPED) 16520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return 0; 16620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset); 16720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 16820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 16920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard) 17020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 17120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 no; 17220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan for_each_phy(phy_mask, phy_mask, no) { 17320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!(phy_mask & 1)) 17420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan continue; 17520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->phy_reset(mvi, no, hard); 17620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 17720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 17820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 17920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, 18020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan void *funcdata) 18120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 18220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int rc = 0, phy_id = sas_phy->id; 18320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 tmp, i = 0, hi; 18420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_ha_struct *sha = sas_phy->ha; 18520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_info *mvi = NULL; 18620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 18720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan while (sha->sas_phy[i]) { 18820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (sha->sas_phy[i] == sas_phy) 18920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 19020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i++; 19120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 19220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy; 19320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi]; 19420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 19520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan switch (func) { 19620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case PHY_FUNC_SET_LINK_RATE: 19720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata); 19820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 1998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 200dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case PHY_FUNC_HARD_RESET: 20120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id); 202dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (tmp & PHY_RST_HARD) 203dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 204a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_HARD_RESET); 205dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 206b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 207dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case PHY_FUNC_LINK_RESET: 20820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->phy_enable(mvi, phy_id); 209a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_SOFT_RESET); 210dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 211b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 212dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case PHY_FUNC_DISABLE: 21320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->phy_disable(mvi, phy_id); 21420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 215dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case PHY_FUNC_RELEASE_SPINUP_HOLD: 216dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik default: 217dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -EOPNOTSUPP; 218b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 21920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan msleep(200); 220b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 221b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 222b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 22320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id, 22420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 off_lo, u32 off_hi, u64 sas_addr) 22520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 22620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 lo = (u32)sas_addr; 22720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 hi = (u32)(sas_addr>>32); 22820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 22920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_lo); 23020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, lo); 23120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_hi); 23220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi); 23320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 23420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 235dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_bytes_dmaed(struct mvs_info *mvi, int i) 236ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei{ 237dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = &mvi->phy[i]; 23820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct asd_sas_phy *sas_phy = &phy->sas_phy; 23920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_ha_struct *sas_ha; 240dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!phy->phy_attached) 241dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return; 242dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 24320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!(phy->att_dev_info & PORT_DEV_TRGT_MASK) 24420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan && phy->phy_type & PORT_TYPE_SAS) { 24520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return; 24620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 24720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 24820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sas_ha = mvi->sas; 24920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE); 25020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 251dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (sas_phy->phy) { 252dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_phy *sphy = sas_phy->phy; 253dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 254dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sphy->negotiated_linkrate = sas_phy->linkrate; 255dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sphy->minimum_linkrate = phy->minimum_linkrate; 256dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; 257dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sphy->maximum_linkrate = phy->maximum_linkrate; 25820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sphy->maximum_linkrate_hw = MVS_CHIP_DISP->phy_max_link_rate(); 259ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei } 260ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei 261dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_type & PORT_TYPE_SAS) { 262dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_identify_frame *id; 263b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 264dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik id = (struct sas_identify_frame *)phy->frame_rcvd; 265dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik id->dev_type = phy->identify.device_type; 266dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik id->initiator_bits = SAS_PROTOCOL_ALL; 267dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik id->target_bits = phy->identify.target_port_protocols; 268477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu 269477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu /* direct attached SAS device */ 270477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu if (phy->att_dev_info & PORT_SSP_TRGT_MASK) { 271477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); 272477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x00); 273477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu } 274dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else if (phy->phy_type & PORT_TYPE_SATA) { 27520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /*Nothing*/ 276dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 27720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("phy %d byte dmaded.\n", i + mvi->id * mvi->chip->n_phy); 27820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 27920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sas_phy->frame_rcvd_size = phy->frame_rcvd_size; 28020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 28120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi->sas->notify_port_event(sas_phy, 282dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PORTE_BYTES_DMAED); 283ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei} 284ee1f1c2ef95258351e1ecb89a2dbd2763cb3a6edKe Wei 285dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikvoid mvs_scan_start(struct Scsi_Host *shost) 286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 28720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int i, j; 28820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned short core_nr; 28920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_info *mvi; 29020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 29184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu struct mvs_prv_info *mvs_prv = sha->lldd_ha; 29220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 29320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; 294dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 29520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan for (j = 0; j < core_nr; j++) { 29620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j]; 29720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan for (i = 0; i < mvi->chip->n_phy; ++i) 29820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_bytes_dmaed(mvi, i); 299dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 30084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mvs_prv->scan_finished = 1; 301b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 302b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 303dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikint mvs_scan_finished(struct Scsi_Host *shost, unsigned long time) 304b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 30584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); 30684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu struct mvs_prv_info *mvs_prv = sha->lldd_ha; 30784fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu 30884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu if (mvs_prv->scan_finished == 0) 309dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 31084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu 311dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik scsi_flush_work(shost); 312dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 1; 313b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 314b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 315dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_smp(struct mvs_info *mvi, 316dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_task_exec_info *tei) 317b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 318dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int elem, rc, i; 319dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_task *task = tei->task; 320dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_cmd_hdr *hdr = tei->hdr; 32120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct domain_device *dev = task->dev; 32220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct asd_sas_port *sas_port = dev->port; 323dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct scatterlist *sg_req, *sg_resp; 324dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 req_len, resp_len, tag = tei->tag; 325dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik void *buf_tmp; 326dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u8 *buf_oaf; 327dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik dma_addr_t buf_tmp_dma; 32820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan void *buf_prd; 329dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_slot_info *slot = &mvi->slot_info[tag]; 330dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); 331b89e8f539ff8bcf2a1464578fa91cb96cc433fc3Xiangliang Yu 332dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* 333dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * DMA-map SMP request, response buffers 334dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik */ 335dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sg_req = &task->smp_task.smp_req; 33620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan elem = dma_map_sg(mvi->dev, sg_req, 1, PCI_DMA_TODEVICE); 337dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!elem) 338dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return -ENOMEM; 339dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik req_len = sg_dma_len(sg_req); 340b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 341dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sg_resp = &task->smp_task.smp_resp; 34220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan elem = dma_map_sg(mvi->dev, sg_resp, 1, PCI_DMA_FROMDEVICE); 343dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!elem) { 344dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -ENOMEM; 345dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out; 346dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 34720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan resp_len = SB_RFB_MAX; 348b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 349dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* must be in dwords */ 350dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if ((req_len & 0x3) || (resp_len & 0x3)) { 351dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik rc = -EINVAL; 352dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik goto err_out_2; 353b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 354b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 355dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* 356dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 357dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik */ 358b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 35920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */ 360dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp = slot->buf; 361dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp_dma = slot->buf_dma; 362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 363dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req)); 364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 365dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ 366dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_oaf = buf_tmp; 367dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->open_frame = cpu_to_le64(buf_tmp_dma); 368b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 369dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp += MVS_OAF_SZ; 370dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp_dma += MVS_OAF_SZ; 371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 37220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* region 3: PRD table *********************************** */ 373dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_prd = buf_tmp; 374dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (tei->n_elem) 375dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 376dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik else 377dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->prd_tbl = 0; 378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 37920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i = MVS_CHIP_DISP->prd_size() * tei->n_elem; 380dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp += i; 381dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik buf_tmp_dma += i; 382b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 383dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ 384dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->response = buf_tmp; 385dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->status_buf = cpu_to_le64(buf_tmp_dma); 38620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvi->flags & MVF_FLAG_SOC) 38720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan hdr->reserved[0] = 0; 388b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 389dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* 390dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik * Fill in TX ring and command slot header 391dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik */ 392dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->tx = mvi->tx_prod; 393dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) | 394dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik TXQ_MODE_I | tag | 395dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik (sas_port->phy_mask << TXQ_PHY_SHIFT)); 396b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 397dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->flags |= flags; 398dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4)); 399dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->tags = cpu_to_le32(tag); 400dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik hdr->data_len = 0; 401b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 402dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* generate open address frame hdr (first 12 bytes) */ 40320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* initiator, SMP, ftype 1h */ 40420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan buf_oaf[0] = (1 << 7) | (PROTOCOL_SMP << 4) | 0x01; 4056ceae7c6234f2961dc59912412e8c0706d825873Xiangliang Yu buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf; 406dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *(u16 *)(buf_oaf + 2) = 0xFFFF; /* SAS SPEC */ 40720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); 408dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 409dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* fill in PRD (scatter/gather) table, if any */ 41020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); 411b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 412b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 413b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 414dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_2: 41520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1, 416dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PCI_DMA_FROMDEVICE); 417b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikerr_out: 41820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1, 419dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PCI_DMA_TODEVICE); 420b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return rc; 4218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 4228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 423dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag) 4248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 425dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct ata_queued_cmd *qc = task->uldd_task; 4268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 427dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (qc) { 428dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (qc->tf.command == ATA_CMD_FPDMA_WRITE || 429dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik qc->tf.command == ATA_CMD_FPDMA_READ) { 430dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik *tag = qc->tag; 431dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 1; 432dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 4338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 4348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 435dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 4368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 4378f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 438dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic int mvs_task_prep_ata(struct mvs_info *mvi, 439dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_task_exec_info *tei) 440b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_task *task = tei->task; 442b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct domain_device *dev = task->dev; 443f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan struct mvs_device *mvi_dev = dev->lldd_dev; 444b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_cmd_hdr *hdr = tei->hdr; 445b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct asd_sas_port *sas_port = dev->port; 4468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct mvs_slot_info *slot; 44720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan void *buf_prd; 44820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 tag = tei->tag, hdr_tag; 44920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 flags, del_q; 450b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *buf_tmp; 451b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 *buf_cmd, *buf_oaf; 452b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t buf_tmp_dma; 4538f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 i, req_len, resp_len; 4548f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei const u32 max_resp_len = SB_RFB_MAX; 4558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 45620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvs_assign_reg_set(mvi, mvi_dev) == MVS_ID_NOT_MAPPED) { 45720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("Have not enough regiset for dev %d.\n", 45820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_dev->device_id); 4598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei return -EBUSY; 46020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 4618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei slot = &mvi->slot_info[tag]; 4628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei slot->tx = mvi->tx_prod; 46320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan del_q = TXQ_MODE_I | tag | 46420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan (TXQ_CMD_STP << TXQ_CMD_SHIFT) | 46520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan (sas_port->phy_mask << TXQ_PHY_SHIFT) | 46620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan (mvi_dev->taskfileset << TXQ_SRS_SHIFT); 46720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q); 46820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 46920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->data_dir == DMA_FROM_DEVICE) 47020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT); 47120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan else 47220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); 4738882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu 474b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (task->ata_task.use_ncq) 475b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags |= MCH_FPDMA; 4768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) { 4778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI) 4788f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei flags |= MCH_ATAPI; 4798f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 4808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 481b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->flags = cpu_to_le32(flags); 4828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 48320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag)) 48420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); 4854e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei else 48620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan hdr_tag = tag; 48720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 48820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan hdr->tags = cpu_to_le32(hdr_tag); 48920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 490b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->data_len = cpu_to_le32(task->total_xfer_len); 491b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 492b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 493b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 494b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 495b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 4968f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */ 4978f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei buf_cmd = buf_tmp = slot->buf; 498b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma = slot->buf_dma; 499b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 500b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); 501b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 502b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_ATA_CMD_SZ; 503b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_ATA_CMD_SZ; 504b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5058f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ 506b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* used for STP. unused for SATA? */ 507b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf = buf_tmp; 508b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->open_frame = cpu_to_le64(buf_tmp_dma); 509b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 510b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_OAF_SZ; 511b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_OAF_SZ; 512b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 3: PRD table ********************************************* */ 514b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd = buf_tmp; 51520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 5168f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (tei->n_elem) 5178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 5188f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei else 5198f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei hdr->prd_tbl = 0; 52020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i = MVS_CHIP_DISP->prd_size() * MVS_CHIP_DISP->prd_count(); 521b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 522b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += i; 523b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += i; 524b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5258f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ 526b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->response = buf_tmp; 527b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->status_buf = cpu_to_le64(buf_tmp_dma); 52820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvi->flags & MVF_FLAG_SOC) 52920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan hdr->reserved[0] = 0; 530b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 5318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei req_len = sizeof(struct host_to_dev_fis); 532b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ - 5338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei sizeof(struct mvs_err_info) - i; 534b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 535b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* request, response lengths */ 5368f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei resp_len = min(resp_len, max_resp_len); 537b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); 538b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 53920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (likely(!task->ata_task.device_control_reg_update)) 54020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ 541b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in command FIS and ATAPI CDB */ 5428f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis)); 5438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) 5448f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei memcpy(buf_cmd + STP_ATAPI_CMD, 5458f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei task->ata_task.atapi_packet, 16); 5468f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 5478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* generate open address frame hdr (first 12 bytes) */ 54820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* initiator, STP, ftype 1h */ 54920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan buf_oaf[0] = (1 << 7) | (PROTOCOL_STP << 4) | 0x1; 5506ceae7c6234f2961dc59912412e8c0706d825873Xiangliang Yu buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf; 55120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1); 55220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); 553b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 554b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* fill in PRD (scatter/gather) table, if any */ 55520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); 5568882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu 55720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->data_dir == DMA_FROM_DEVICE) 5588882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu MVS_CHIP_DISP->dma_fix(mvi, sas_port->phy_mask, 55920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan TRASH_BUCKET_SIZE, tei->n_elem, buf_prd); 5608882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu 561b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 562b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 563b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 564b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzikstatic int mvs_task_prep_ssp(struct mvs_info *mvi, 56520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_task_exec_info *tei, int is_tmf, 56620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_tmf_task *tmf) 567b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 568b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct sas_task *task = tei->task; 569b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_cmd_hdr *hdr = tei->hdr; 5708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct mvs_port *port = tei->port; 57120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct domain_device *dev = task->dev; 572f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan struct mvs_device *mvi_dev = dev->lldd_dev; 57320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct asd_sas_port *sas_port = dev->port; 574b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_slot_info *slot; 57520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan void *buf_prd; 576b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct ssp_frame_hdr *ssp_hdr; 577b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik void *buf_tmp; 578b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u8 *buf_cmd, *buf_oaf, fburst = 0; 579b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik dma_addr_t buf_tmp_dma; 580b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik u32 flags; 5818f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei u32 resp_len, req_len, i, tag = tei->tag; 5828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei const u32 max_resp_len = SB_RFB_MAX; 58320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 phy_mask; 584b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 585b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot = &mvi->slot_info[tag]; 586b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 58720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy_mask = ((port->wide_port_phymap) ? port->wide_port_phymap : 58820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sas_port->phy_mask) & TXQ_PHY_MASK; 58920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 5908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei slot->tx = mvi->tx_prod; 5918f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag | 5928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei (TXQ_CMD_SSP << TXQ_CMD_SHIFT) | 5934e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei (phy_mask << TXQ_PHY_SHIFT)); 594b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 595b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags = MCH_RETRY; 596b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik if (task->ssp_task.enable_first_burst) { 597b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik flags |= MCH_FBURST; 598b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik fburst = (1 << 7); 599b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 6002b288133ab6306b1761e0a2ef943b944ead6ad69Andy Yan if (is_tmf) 6012b288133ab6306b1761e0a2ef943b944ead6ad69Andy Yan flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT); 60284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu else 60384fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT); 60484fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu 6052b288133ab6306b1761e0a2ef943b944ead6ad69Andy Yan hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT)); 606b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->tags = cpu_to_le32(tag); 607b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->data_len = cpu_to_le32(task->total_xfer_len); 608b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 609b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* 610b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs 611b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik */ 612b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */ 6148f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei buf_cmd = buf_tmp = slot->buf; 615b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma = slot->buf_dma; 616b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 617b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); 618b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 619b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_SSP_CMD_SZ; 620b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_SSP_CMD_SZ; 621b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6228f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ 623b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_oaf = buf_tmp; 624b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->open_frame = cpu_to_le64(buf_tmp_dma); 625b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 626b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += MVS_OAF_SZ; 627b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += MVS_OAF_SZ; 628b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6298f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 3: PRD table ********************************************* */ 630b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_prd = buf_tmp; 6318f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei if (tei->n_elem) 6328f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); 6338f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei else 6348f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei hdr->prd_tbl = 0; 635b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 63620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i = MVS_CHIP_DISP->prd_size() * tei->n_elem; 637b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp += i; 638b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_tmp_dma += i; 639b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6408f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ 641b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik slot->response = buf_tmp; 642b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->status_buf = cpu_to_le64(buf_tmp_dma); 64320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvi->flags & MVF_FLAG_SOC) 64420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan hdr->reserved[0] = 0; 645b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 646b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ - 6478f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei sizeof(struct mvs_err_info) - i; 6488f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei resp_len = min(resp_len, max_resp_len); 6498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 6508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei req_len = sizeof(struct ssp_frame_hdr) + 28; 651b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 652b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* request, response lengths */ 653b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); 654b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 655b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik /* generate open address frame hdr (first 12 bytes) */ 65620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* initiator, SSP, ftype 1h */ 65720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan buf_oaf[0] = (1 << 7) | (PROTOCOL_SSP << 4) | 0x1; 6586ceae7c6234f2961dc59912412e8c0706d825873Xiangliang Yu buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf; 65920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1); 66020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); 661b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 6628f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei /* fill in SSP frame header (Command Table.SSP frame header) */ 6638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei ssp_hdr = (struct ssp_frame_hdr *)buf_cmd; 66420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 66520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (is_tmf) 66620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan ssp_hdr->frame_type = SSP_TASK; 66720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan else 66820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan ssp_hdr->frame_type = SSP_COMMAND; 66920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 67020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr, 671b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik HASHED_SAS_ADDR_SIZE); 672b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(ssp_hdr->hashed_src_addr, 67320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); 674b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik ssp_hdr->tag = cpu_to_be16(tag); 675b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 67620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* fill in IU for TASK and Command Frame */ 677b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik buf_cmd += sizeof(*ssp_hdr); 678b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik memcpy(buf_cmd, &task->ssp_task.LUN, 8); 679b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 68020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (ssp_hdr->frame_type != SSP_TASK) { 68120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan buf_cmd[9] = fburst | task->ssp_task.task_attr | 68220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan (task->ssp_task.task_prio << 3); 68320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16); 68420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else{ 68520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan buf_cmd[10] = tmf->tmf; 68620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan switch (tmf->tmf) { 68720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case TMF_ABORT_TASK: 68820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case TMF_QUERY_TASK: 68920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan buf_cmd[12] = 69020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan (tmf->tag_of_task_to_be_managed >> 8) & 0xff; 69120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan buf_cmd[13] = 69220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmf->tag_of_task_to_be_managed & 0xff; 69320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 69420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan default: 69520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 69620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 697b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 69820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* fill in PRD (scatter/gather) table, if any */ 69920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); 700b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik return 0; 701b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 702b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 70320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE))) 7040b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf, 7050b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_tmf_task *tmf, int *pass) 706b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 7078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei struct domain_device *dev = task->dev; 7080b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_device *mvi_dev = dev->lldd_dev; 709b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik struct mvs_task_exec_info tei; 7104e52fc0a0a2ec2158691efba3f149f6416481255Ke Wei struct mvs_slot_info *slot; 7110b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu u32 tag = 0xdeadbeef, n_elem = 0; 7120b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu int rc = 0; 713b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 71420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!dev->port) { 7150b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct task_status_struct *tsm = &task->task_status; 71620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 71720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tsm->resp = SAS_TASK_UNDELIVERED; 71820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tsm->stat = SAS_PHY_DOWN; 7190b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu /* 7200b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu * libsas will use dev->port, should 7210b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu * not call task_done for sata 7220b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu */ 7239dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (dev->dev_type != SATA_DEV) 7240b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->task_done(task); 7250b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu return rc; 72620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 72720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 7280b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (DEV_IS_GONE(mvi_dev)) { 7290b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (mvi_dev) 7300b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mv_dprintk("device %d not ready.\n", 7310b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mvi_dev->device_id); 7320b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu else 7330b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mv_dprintk("device %016llx not ready.\n", 7340b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu SAS_ADDR(dev->sas_addr)); 73520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 73620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = SAS_PHY_DOWN; 7370b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu return rc; 7380b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 7390b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu tei.port = dev->port->lldd_port; 7400b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (tei.port && !tei.port->port_attached && !tmf) { 7410b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (sas_protocol_ata(task->task_proto)) { 7420b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct task_status_struct *ts = &task->task_status; 7430b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mv_dprintk("SATA/STP port %d does not attach" 7440b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu "device.\n", dev->port->id); 7450b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu ts->resp = SAS_TASK_COMPLETE; 7460b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu ts->stat = SAS_PHY_DOWN; 74720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 7480b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->task_done(task); 749dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 750dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else { 7510b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct task_status_struct *ts = &task->task_status; 7520b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mv_dprintk("SAS port %d does not attach" 7530b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu "device.\n", dev->port->id); 7540b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu ts->resp = SAS_TASK_UNDELIVERED; 7550b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu ts->stat = SAS_PHY_DOWN; 7560b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->task_done(task); 757dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 7580b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu return rc; 7590b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 760dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 7610b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (!sas_protocol_ata(task->task_proto)) { 7620b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (task->num_scatter) { 7630b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu n_elem = dma_map_sg(mvi->dev, 7640b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->scatter, 7650b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->num_scatter, 7660b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->data_dir); 7670b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (!n_elem) { 7680b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu rc = -ENOMEM; 7690b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu goto prep_out; 7700b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 7710b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 7720b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } else { 7730b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu n_elem = task->num_scatter; 7740b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 77520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 7760b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu rc = mvs_tag_alloc(mvi, &tag); 7770b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (rc) 7780b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu goto err_out; 77920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 7800b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu slot = &mvi->slot_info[tag]; 78120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 7820b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->lldd_task = NULL; 7830b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu slot->n_elem = n_elem; 7840b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu slot->slot_tag = tag; 7850b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 7860b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu slot->buf = pci_pool_alloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma); 7870b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (!slot->buf) 7880b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu goto err_out_tag; 7890b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu memset(slot->buf, 0, MVS_SLOT_BUF_SZ); 7900b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 7910b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu tei.task = task; 7920b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu tei.hdr = &mvi->slot[tag]; 7930b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu tei.tag = tag; 7940b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu tei.n_elem = n_elem; 7950b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu switch (task->task_proto) { 7960b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu case SAS_PROTOCOL_SMP: 7970b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu rc = mvs_task_prep_smp(mvi, &tei); 7980b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu break; 7990b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu case SAS_PROTOCOL_SSP: 8000b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf); 8010b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu break; 8020b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu case SAS_PROTOCOL_SATA: 8030b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu case SAS_PROTOCOL_STP: 8040b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: 8050b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu rc = mvs_task_prep_ata(mvi, &tei); 8060b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu break; 8070b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu default: 8080b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu dev_printk(KERN_ERR, mvi->dev, 8090b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu "unknown sas_task proto: 0x%x\n", 8100b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->task_proto); 8110b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu rc = -EINVAL; 8120b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu break; 8130b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 814dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 8150b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (rc) { 8160b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mv_dprintk("rc is %x\n", rc); 8170b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu goto err_out_slot_buf; 8180b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 8190b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu slot->task = task; 8200b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu slot->port = tei.port; 8210b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->lldd_task = slot; 8220b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu list_add_tail(&slot->entry, &tei.port->list); 8230b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu spin_lock(&task->task_state_lock); 8240b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->task_state_flags |= SAS_TASK_AT_INITIATOR; 8250b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu spin_unlock(&task->task_state_lock); 8260b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8270b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mvi_dev->running_req++; 8280b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu ++(*pass); 8290b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); 8309dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 8310b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu return rc; 832dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 8330b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yuerr_out_slot_buf: 8340b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); 835dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out_tag: 836dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_free(mvi, tag); 837dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikerr_out: 83820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 8390b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc); 8400b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (!sas_protocol_ata(task->task_proto)) 841dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (n_elem) 8420b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu dma_unmap_sg(mvi->dev, task->scatter, n_elem, 8430b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu task->data_dir); 8440b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yuprep_out: 8450b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu return rc; 8460b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu} 8470b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8480b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic struct mvs_task_list *mvs_task_alloc_list(int *num, gfp_t gfp_flags) 8490b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu{ 8500b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_task_list *first = NULL; 8510b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8520b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu for (; *num > 0; --*num) { 8530b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_task_list *mvs_list = kmem_cache_zalloc(mvs_task_list_cache, gfp_flags); 8540b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8550b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (!mvs_list) 8560b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu break; 8570b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8580b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu INIT_LIST_HEAD(&mvs_list->list); 8590b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (!first) 8600b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu first = mvs_list; 8610b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu else 8620b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu list_add_tail(&mvs_list->list, &first->list); 8630b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8640b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 8650b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8660b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu return first; 8670b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu} 8680b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8690b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic inline void mvs_task_free_list(struct mvs_task_list *mvs_list) 8700b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu{ 8710b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu LIST_HEAD(list); 8720b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct list_head *pos, *a; 8730b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_task_list *mlist = NULL; 8740b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8750b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu __list_add(&list, mvs_list->list.prev, &mvs_list->list); 8760b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8770b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu list_for_each_safe(pos, a, &list) { 8780b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu list_del_init(pos); 8790b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mlist = list_entry(pos, struct mvs_task_list, list); 8800b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu kmem_cache_free(mvs_task_list_cache, mlist); 8810b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 8820b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu} 8830b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8840b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, 8850b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct completion *completion, int is_tmf, 8860b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_tmf_task *tmf) 8870b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu{ 8880b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct domain_device *dev = task->dev; 8890b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_info *mvi = NULL; 8900b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu u32 rc = 0; 8910b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu u32 pass = 0; 8920b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu unsigned long flags = 0; 8930b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8940b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info; 8950b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8960b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL)) 8970b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu spin_unlock_irq(dev->sata_dev.ap->lock); 8980b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 8990b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu spin_lock_irqsave(&mvi->lock, flags); 9000b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass); 9010b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (rc) 9020b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); 9030b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9040b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (likely(pass)) 9050b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) & 9060b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu (MVS_CHIP_SLOT_SZ - 1)); 9070b84b7094e87769120def1e703b8b4d037281038Andy Yan spin_unlock_irqrestore(&mvi->lock, flags); 9080b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9090b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if ((dev->dev_type == SATA_DEV) && (dev->sata_dev.ap != NULL)) 9100b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu spin_lock_irq(dev->sata_dev.ap->lock); 9110b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9120b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu return rc; 9130b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu} 9140b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9150b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yustatic int mvs_collector_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, 9160b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct completion *completion, int is_tmf, 9170b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_tmf_task *tmf) 9180b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu{ 9190b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct domain_device *dev = task->dev; 9200b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_prv_info *mpi = dev->port->ha->lldd_ha; 9210b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_info *mvi = NULL; 9220b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct sas_task *t = task; 9230b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_task_list *mvs_list = NULL, *a; 9240b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu LIST_HEAD(q); 9250b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu int pass[2] = {0}; 9260b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu u32 rc = 0; 9270b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu u32 n = num; 9280b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu unsigned long flags = 0; 9290b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9300b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mvs_list = mvs_task_alloc_list(&n, gfp_flags); 9310b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (n) { 9320b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu printk(KERN_ERR "%s: mvs alloc list failed.\n", __func__); 9330b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu rc = -ENOMEM; 9340b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu goto free_list; 9350b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 9360b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9370b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu __list_add(&q, mvs_list->list.prev, &mvs_list->list); 9380b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9390b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu list_for_each_entry(a, &q, list) { 9400b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu a->task = t; 9410b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu t = list_entry(t->list.next, struct sas_task, list); 9420b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 9430b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9440b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu list_for_each_entry(a, &q , list) { 9450b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9460b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu t = a->task; 9470b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mvi = ((struct mvs_device *)t->dev->lldd_dev)->mvi_info; 9480b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9490b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu spin_lock_irqsave(&mvi->lock, flags); 9500b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu rc = mvs_task_prep(t, mvi, is_tmf, tmf, &pass[mvi->id]); 9510b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (rc) 9520b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); 9530b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu spin_unlock_irqrestore(&mvi->lock, flags); 9540b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 9550b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9560b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (likely(pass[0])) 9570b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu MVS_CHIP_DISP->start_delivery(mpi->mvi[0], 9580b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu (mpi->mvi[0]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); 9590b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9600b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (likely(pass[1])) 9610b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu MVS_CHIP_DISP->start_delivery(mpi->mvi[1], 9620b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu (mpi->mvi[1]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); 9630b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9640b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu list_del_init(&q); 9650b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9660b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yufree_list: 9670b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (mvs_list) 9680b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu mvs_task_free_list(mvs_list); 9690b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 970dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return rc; 971dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 972dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 97320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_queue_command(struct sas_task *task, const int num, 97420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan gfp_t gfp_flags) 97520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 9760b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct mvs_device *mvi_dev = task->dev->lldd_dev; 9770b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu struct sas_ha_struct *sas = mvi_dev->mvi_info->sas; 9780b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 9790b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (sas->lldd_max_execute_num < 2) 9800b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL); 9810b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu else 9820b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu return mvs_collector_task_exec(task, num, gfp_flags, NULL, 0, NULL); 98320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 98420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 985dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) 986dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 987dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 slot_idx = rx_desc & RXQ_SLOT_MASK; 988dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_tag_clear(mvi, slot_idx); 989dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 990dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 991dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, 992dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_slot_info *slot, u32 slot_idx) 993dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 99420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!slot->task) 99520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return; 996dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!sas_protocol_ata(task->task_proto)) 997dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (slot->n_elem) 99820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan dma_unmap_sg(mvi->dev, task->scatter, 999dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->n_elem, task->data_dir); 1000dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1001dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik switch (task->task_proto) { 1002dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SMP: 100320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1, 1004dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PCI_DMA_FROMDEVICE); 100520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1, 1006dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik PCI_DMA_TODEVICE); 1007dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1008dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1009dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA: 1010dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_STP: 1011dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SSP: 1012dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik default: 1013dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik /* do nothing */ 1014dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1015dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 10160b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu 10170b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu if (slot->buf) { 10180b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); 10190b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu slot->buf = NULL; 10200b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu } 102120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan list_del_init(&slot->entry); 1022dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik task->lldd_task = NULL; 1023dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->task = NULL; 1024dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik slot->port = NULL; 102520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan slot->slot_tag = 0xFFFFFFFF; 102620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_slot_free(mvi, slot_idx); 1027dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1028dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 102984fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yustatic void mvs_update_wideport(struct mvs_info *mvi, int phy_no) 1030dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 103184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu struct mvs_phy *phy = &mvi->phy[phy_no]; 1032dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_port *port = phy->port; 1033dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik int j, no; 1034dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 103520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan for_each_phy(port->wide_port_phymap, j, no) { 103620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (j & 1) { 103720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_addr(mvi, no, 103820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan PHYR_WIDE_PORT); 103920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_data(mvi, no, 1040dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->wide_port_phymap); 1041dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else { 104220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_addr(mvi, no, 104320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan PHYR_WIDE_PORT); 104420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_data(mvi, no, 104520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 0); 1046dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 104720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 1048dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1049dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1050dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_phy_ready(struct mvs_info *mvi, int i) 1051dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1052dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 tmp; 1053dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = &mvi->phy[i]; 105420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_port *port = phy->port; 1055dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 105620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, i); 1057dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) { 1058dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!port) 1059dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_attached = 1; 1060dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return tmp; 1061dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1062dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1063dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (port) { 1064dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_type & PORT_TYPE_SAS) { 1065dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->wide_port_phymap &= ~(1U << i); 1066dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!port->wide_port_phymap) 1067dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->port_attached = 0; 1068dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_update_wideport(mvi, i); 1069dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } else if (phy->phy_type & PORT_TYPE_SATA) 1070dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->port_attached = 0; 1071dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->port = NULL; 1072dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_attached = 0; 1073dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); 1074dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1075dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return 0; 1076dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1077dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1078dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) 1079dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1080dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik u32 *s = (u32 *) buf; 1081dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1082dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (!s) 1083dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return NULL; 1084dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 108520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3); 108684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu s[3] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); 1087dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 108820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2); 108984fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu s[2] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); 1090dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 109120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1); 109284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu s[1] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); 1093dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 109420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0); 109584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu s[0] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); 109620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 109720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01)) 109820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10); 1099dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1100f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan return s; 1101dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1102dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1103dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzikstatic u32 mvs_is_sig_fis_received(u32 irq_status) 1104dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1105dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return irq_status & PHYEV_SIG_FIS; 1106dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1107dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 11088882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yustatic void mvs_sig_remove_timer(struct mvs_phy *phy) 11098882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu{ 11108882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu if (phy->timer.function) 11118882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu del_timer(&phy->timer); 11128882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu phy->timer.function = NULL; 11138882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu} 11148882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu 111520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st) 1116dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1117dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = &mvi->phy[i]; 111820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_identify_frame *id; 1119b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 112020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan id = (struct sas_identify_frame *)phy->frame_rcvd; 1121b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1122dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (get_st) { 112320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, i); 1124dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->phy_status = mvs_is_phy_ready(mvi, i); 1125dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 11268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1127dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_status) { 112820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int oob_done = 0; 112920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct asd_sas_phy *sas_phy = &mvi->phy[i].sas_phy; 1130b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 113120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan oob_done = MVS_CHIP_DISP->oob_done(mvi, i); 113220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 113320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->fix_phy_info(mvi, i, id); 113420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy->phy_type & PORT_TYPE_SATA) { 113520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->identify.target_port_protocols = SAS_PROTOCOL_STP; 113620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvs_is_sig_fis_received(phy->irq_status)) { 11378882f081329a82737b7471b97e59ce8c407f6655Xiangliang Yu mvs_sig_remove_timer(phy); 113820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->phy_attached = 1; 113920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->att_dev_sas_addr = 114020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i + mvi->id * mvi->chip->n_phy; 114120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (oob_done) 114220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sas_phy->oob_mode = SATA_OOB_MODE; 114320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->frame_rcvd_size = 114420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sizeof(struct dev_to_host_fis); 1145f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan mvs_get_d2h_reg(mvi, i, id); 114620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else { 114720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 tmp; 114820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan dev_printk(KERN_DEBUG, mvi->dev, 114920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan "Phy%d : No sig fis\n", i); 115020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, i); 115120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_irq_mask(mvi, i, 115220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmp | PHYEV_SIG_FIS); 115320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->phy_attached = 0; 115420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->phy_type &= ~PORT_TYPE_SATA; 115520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan goto out_done; 115620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 11579dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas } else if (phy->phy_type & PORT_TYPE_SAS 115820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan || phy->att_dev_info & PORT_SSP_INIT_MASK) { 115920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->phy_attached = 1; 1160dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->identify.device_type = 116120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->att_dev_info & PORT_DEV_TYPE_MASK; 1162b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1163dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->identify.device_type == SAS_END_DEV) 1164dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->identify.target_port_protocols = 1165dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik SAS_PROTOCOL_SSP; 1166dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik else if (phy->identify.device_type != NO_DEVICE) 1167dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->identify.target_port_protocols = 1168dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik SAS_PROTOCOL_SMP; 116920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (oob_done) 1170dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sas_phy->oob_mode = SAS_OOB_MODE; 1171dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->frame_rcvd_size = 1172dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik sizeof(struct sas_identify_frame); 1173dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 117420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memcpy(sas_phy->attached_sas_addr, 117520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan &phy->att_dev_sas_addr, SAS_ADDR_SIZE); 1176b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 117720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (MVS_CHIP_DISP->phy_work_around) 117820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->phy_work_around(mvi, i); 1179dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 118084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mv_dprintk("phy %d attach dev info is %x\n", 118120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i + mvi->id * mvi->chip->n_phy, phy->att_dev_info); 118284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mv_dprintk("phy %d attach sas addr is %llx\n", 118320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr); 11844e52fc0a0a2ec2158691efba3f149f6416481255Ke Weiout_done: 1185dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (get_st) 118620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_irq_stat(mvi, i, phy->irq_status); 1187b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1188b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 118920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock) 11908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 1191dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct sas_ha_struct *sas_ha = sas_phy->ha; 119220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_info *mvi = NULL; int i = 0, hi; 1193dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik struct mvs_phy *phy = sas_phy->lldd_phy; 119420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct asd_sas_port *sas_port = sas_phy->port; 119520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_port *port; 119620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned long flags = 0; 119720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!sas_port) 119820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return; 11998f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 120020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan while (sas_ha->sas_phy[i]) { 120120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (sas_ha->sas_phy[i] == sas_phy) 120220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 120320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan i++; 120420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 120520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy; 120620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi]; 120784fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu if (i >= mvi->chip->n_phy) 120884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu port = &mvi->port[i - mvi->chip->n_phy]; 120920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan else 121084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu port = &mvi->port[i]; 121120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (lock) 121220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_lock_irqsave(&mvi->lock, flags); 1213dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->port_attached = 1; 1214dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik phy->port = port; 12150b15fb1fdfd403726542cb6111bc916b7a9f7fadXiangliang Yu sas_port->lldd_port = port; 1216dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik if (phy->phy_type & PORT_TYPE_SAS) { 1217dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik port->wide_port_phymap = sas_port->phy_mask; 121820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("set wide port phy map %x\n", sas_port->phy_mask); 1219dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik mvs_update_wideport(mvi, sas_phy->id); 1220477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu 1221477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu /* direct attached SAS device */ 1222477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu if (phy->att_dev_info & PORT_SSP_TRGT_MASK) { 1223477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); 1224477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x04); 1225477f6d190bdebc9a3ec99e4bb396b981f747bf19Xiangliang Yu } 12268f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 122720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (lock) 122820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_unlock_irqrestore(&mvi->lock, flags); 1229dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1230dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 123120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock) 1232dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 12339dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas struct domain_device *dev; 12349dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas struct mvs_phy *phy = sas_phy->lldd_phy; 12359dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas struct mvs_info *mvi = phy->mvi; 12369dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas struct asd_sas_port *port = sas_phy->port; 12379dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas int phy_no = 0; 12389dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 12399dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas while (phy != &mvi->phy[phy_no]) { 12409dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas phy_no++; 12419dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (phy_no >= MVS_MAX_PHYS) 12429dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas return; 12439dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas } 12449dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas list_for_each_entry(dev, &port->dev_list, dev_list_node) 124584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mvs_do_release_task(phy->mvi, phy_no, dev); 12469dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 1247dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1248dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 1249dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 125020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_port_formed(struct asd_sas_phy *sas_phy) 125120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 125220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_port_notify_formed(sas_phy, 1); 1253dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1254dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 125520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_port_deformed(struct asd_sas_phy *sas_phy) 1256dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 125720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_port_notify_deformed(sas_phy, 1); 125820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 12598f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 126020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstruct mvs_device *mvs_alloc_dev(struct mvs_info *mvi) 126120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 126220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 dev; 126320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan for (dev = 0; dev < MVS_MAX_DEVICES; dev++) { 126420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvi->devices[dev].dev_type == NO_DEVICE) { 126520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi->devices[dev].device_id = dev; 126620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return &mvi->devices[dev]; 126720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 12688f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei } 12698121ed420285885654af133a6ca1919590f98917Ke Wei 127020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (dev == MVS_MAX_DEVICES) 127120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("max support %d devices, ignore ..\n", 127220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_MAX_DEVICES); 127320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 127420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return NULL; 12758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 12768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 127720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_free_dev(struct mvs_device *mvi_dev) 1278b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 127920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 id = mvi_dev->device_id; 128020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memset(mvi_dev, 0, sizeof(*mvi_dev)); 128120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_dev->device_id = id; 128220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_dev->dev_type = NO_DEVICE; 128320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_dev->dev_status = MVS_DEV_NORMAL; 128420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_dev->taskfileset = MVS_ID_NOT_MAPPED; 128520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 1286b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 128720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_dev_found_notify(struct domain_device *dev, int lock) 128820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 128920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned long flags = 0; 129020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int res = 0; 129120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_info *mvi = NULL; 129220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct domain_device *parent_dev = dev->parent; 129320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_device *mvi_device; 1294b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 129520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi = mvs_find_dev_mvi(dev); 1296b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 129720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (lock) 129820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_lock_irqsave(&mvi->lock, flags); 129920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 130020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_device = mvs_alloc_dev(mvi); 130120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!mvi_device) { 130220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan res = -1; 130320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan goto found_out; 1304b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1305f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan dev->lldd_dev = mvi_device; 13069dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvi_device->dev_status = MVS_DEV_NORMAL; 130720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_device->dev_type = dev->dev_type; 13089870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan mvi_device->mvi_info = mvi; 130984fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mvi_device->sas_device = dev; 131020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { 131120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int phy_id; 131220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u8 phy_num = parent_dev->ex_dev.num_phys; 131320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct ex_phy *phy; 131420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan for (phy_id = 0; phy_id < phy_num; phy_id++) { 131520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy = &parent_dev->ex_dev.ex_phy[phy_id]; 131620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (SAS_ADDR(phy->attached_sas_addr) == 131720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan SAS_ADDR(dev->sas_addr)) { 131820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_device->attached_phy = phy_id; 131920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 132020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 132120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 1322b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 132320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy_id == phy_num) { 132420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("Error: no attached dev:%016llx" 132520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan "at ex:%016llx.\n", 132620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan SAS_ADDR(dev->sas_addr), 132720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan SAS_ADDR(parent_dev->sas_addr)); 132820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan res = -1; 132920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 1330dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1331b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 133220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanfound_out: 133320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (lock) 133420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_unlock_irqrestore(&mvi->lock, flags); 133520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return res; 133620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 1337b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 133820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_dev_found(struct domain_device *dev) 133920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 134020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return mvs_dev_found_notify(dev, 1); 134120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 1342b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 13439dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivasvoid mvs_dev_gone_notify(struct domain_device *dev) 134420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 134520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned long flags = 0; 1346f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan struct mvs_device *mvi_dev = dev->lldd_dev; 13479870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan struct mvs_info *mvi = mvi_dev->mvi_info; 1348b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 13499dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas spin_lock_irqsave(&mvi->lock, flags); 1350b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 135120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvi_dev) { 135220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("found dev[%d:%x] is gone.\n", 135320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_dev->device_id, mvi_dev->dev_type); 13549dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvs_release_task(mvi, dev); 135520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_free_reg_set(mvi, mvi_dev); 135620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_free_dev(mvi_dev); 135720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else { 135820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("found dev has gone.\n"); 1359b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 136020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan dev->lldd_dev = NULL; 136184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mvi_dev->sas_device = NULL; 1362b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 13639dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas spin_unlock_irqrestore(&mvi->lock, flags); 1364b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1365b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1366b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 136720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_dev_gone(struct domain_device *dev) 136820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 13699dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvs_dev_gone_notify(dev); 137020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 1371b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 137220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_task_done(struct sas_task *task) 137320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 137420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!del_timer(&task->timer)) 137520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return; 137620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan complete(&task->completion); 1377b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 1378b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 137920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_tmf_timedout(unsigned long data) 1380b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 138120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_task *task = (struct sas_task *)data; 13828f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 138320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_state_flags |= SAS_TASK_STATE_ABORTED; 138420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan complete(&task->completion); 138520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 13868f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 138720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan#define MVS_TASK_TIMEOUT 20 138820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_exec_internal_tmf_task(struct domain_device *dev, 138920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan void *parameter, u32 para_len, struct mvs_tmf_task *tmf) 139020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 139120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int res, retry; 139220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_task *task = NULL; 13938f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 139420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan for (retry = 0; retry < 3; retry++) { 13954fcf812ca392303aa79dd50e96e83a29faa13bd0Dan Williams task = sas_alloc_task(GFP_KERNEL); 139620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!task) 139720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return -ENOMEM; 13988f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 139920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->dev = dev; 140020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_proto = dev->tproto; 14018f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 140220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memcpy(&task->ssp_task, parameter, para_len); 140320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_done = mvs_task_done; 14048f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 140520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->timer.data = (unsigned long) task; 140620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->timer.function = mvs_tmf_timedout; 140720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ; 140820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan add_timer(&task->timer); 14098f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 14100b84b7094e87769120def1e703b8b4d037281038Andy Yan res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf); 14118f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 141220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (res) { 141320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan del_timer(&task->timer); 141420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("executing internel task failed:%d\n", res); 141520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan goto ex_err; 141620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 14178f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 141820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan wait_for_completion(&task->completion); 141984fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu res = TMF_RESP_FUNC_FAILED; 142020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* Even TMF timed out, return direct. */ 142120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { 142220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { 142320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("TMF task[%x] timeout.\n", tmf->tmf); 142420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan goto ex_err; 142520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 142620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 14278f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 142820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->task_status.resp == SAS_TASK_COMPLETE && 1429df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley task->task_status.stat == SAM_STAT_GOOD) { 143020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan res = TMF_RESP_FUNC_COMPLETE; 143120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 143220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 1433b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 143420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->task_status.resp == SAS_TASK_COMPLETE && 143520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_status.stat == SAS_DATA_UNDERRUN) { 143620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* no error, but return the number of bytes of 143720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * underrun */ 143820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan res = task->task_status.residual; 143920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 144020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 1441b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 144220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->task_status.resp == SAS_TASK_COMPLETE && 144320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_status.stat == SAS_DATA_OVERRUN) { 144420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("blocked task error.\n"); 144520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan res = -EMSGSIZE; 144620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 144720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else { 144820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk(" task to dev %016llx response: 0x%x " 144920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan "status 0x%x\n", 145020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan SAS_ADDR(dev->sas_addr), 145120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_status.resp, 145220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_status.stat); 14534fcf812ca392303aa79dd50e96e83a29faa13bd0Dan Williams sas_free_task(task); 145420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task = NULL; 1455b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1456dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1457dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 145820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanex_err: 145920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan BUG_ON(retry == 3 && task != NULL); 14604fcf812ca392303aa79dd50e96e83a29faa13bd0Dan Williams sas_free_task(task); 146120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return res; 1462dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 1463b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 146420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_debug_issue_ssp_tmf(struct domain_device *dev, 146520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u8 *lun, struct mvs_tmf_task *tmf) 1466dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 146720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_ssp_task ssp_task; 146820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!(dev->tproto & SAS_PROTOCOL_SSP)) 146920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return TMF_RESP_FUNC_ESUPP; 1470b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 147184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu memcpy(ssp_task.LUN, lun, 8); 1472b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 147320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return mvs_exec_internal_tmf_task(dev, &ssp_task, 147420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sizeof(ssp_task), tmf); 147520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 14768f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 14778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 147820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* Standard mandates link reset for ATA (type 0) 147920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan and hard reset for SSP (type 1) , only for RECOVERY */ 148020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_debug_I_T_nexus_reset(struct domain_device *dev) 148120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 148220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int rc; 148320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_phy *phy = sas_find_local_phy(dev); 148420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int reset_type = (dev->dev_type == SATA_DEV || 148520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1; 148620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = sas_phy_reset(phy, reset_type); 148720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan msleep(2000); 148820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return rc; 148920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 14908f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 149120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* mandatory SAM-3 */ 149220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_lu_reset(struct domain_device *dev, u8 *lun) 149320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 149420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned long flags; 149584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu int rc = TMF_RESP_FUNC_FAILED; 149620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_tmf_task tmf_task; 1497f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan struct mvs_device * mvi_dev = dev->lldd_dev; 14989870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan struct mvs_info *mvi = mvi_dev->mvi_info; 149920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 150020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmf_task.tmf = TMF_LU_RESET; 150120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_dev->dev_status = MVS_DEV_EH; 150220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); 150320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (rc == TMF_RESP_FUNC_COMPLETE) { 150420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_lock_irqsave(&mvi->lock, flags); 150584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mvs_release_task(mvi, dev); 150620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_unlock_irqrestore(&mvi->lock, flags); 1507dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 150820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* If failed, fall-through I_T_Nexus reset */ 150920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("%s for device[%x]:rc= %d\n", __func__, 151020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi_dev->device_id, rc); 151120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return rc; 151220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 15138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 151420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_I_T_nexus_reset(struct domain_device *dev) 151520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 151620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned long flags; 15179dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas int rc = TMF_RESP_FUNC_FAILED; 15189dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev; 15199870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan struct mvs_info *mvi = mvi_dev->mvi_info; 152020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 152120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvi_dev->dev_status != MVS_DEV_EH) 152220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return TMF_RESP_FUNC_COMPLETE; 152384fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu else 152484fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mvi_dev->dev_status = MVS_DEV_NORMAL; 152520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = mvs_debug_I_T_nexus_reset(dev); 152620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("%s for device[%x]:rc= %d\n", 152720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan __func__, mvi_dev->device_id, rc); 152820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 152920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_lock_irqsave(&mvi->lock, flags); 15309dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvs_release_task(mvi, dev); 153120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_unlock_irqrestore(&mvi->lock, flags); 153220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 153320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return rc; 153420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 153520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* optional SAM-3 */ 153620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_query_task(struct sas_task *task) 153720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 153820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 tag; 153920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct scsi_lun lun; 154020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_tmf_task tmf_task; 154120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int rc = TMF_RESP_FUNC_FAILED; 154220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 154320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { 154420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task; 154520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct domain_device *dev = task->dev; 15469870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; 15479870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan struct mvs_info *mvi = mvi_dev->mvi_info; 154820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 154920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int_to_scsilun(cmnd->device->lun, &lun); 155020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = mvs_find_tag(mvi, task, &tag); 155120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (rc == 0) { 155220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = TMF_RESP_FUNC_FAILED; 1553dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return rc; 155420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 15558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 155620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmf_task.tmf = TMF_QUERY_TASK; 155720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); 15588f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 155920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task); 156020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan switch (rc) { 156120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* The task is still in Lun, release it then */ 156220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case TMF_RESP_FUNC_SUCC: 156320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* The task is not in Lun or failed, reset the phy */ 156420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case TMF_RESP_FUNC_FAILED: 156520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case TMF_RESP_FUNC_COMPLETE: 156620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 156720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 1568dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 156920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("%s:rc= %d\n", __func__, rc); 157020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return rc; 15718f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 15728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 157320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan/* mandatory SAM-3, still need free task/slot info */ 157420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_abort_task(struct sas_task *task) 15758f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 157620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct scsi_lun lun; 157720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_tmf_task tmf_task; 157820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct domain_device *dev = task->dev; 15799870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; 158024ae163ed33d2b8a70d2f0b1947b401d0a8e8719Jiri Slaby struct mvs_info *mvi; 158120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int rc = TMF_RESP_FUNC_FAILED; 158220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned long flags; 158320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 tag; 15849870d9a2428550e7ac3164a26306ad07a99051aeAndy Yan 15859dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (!mvi_dev) { 158684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mv_printk("Device has removed\n"); 158784fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu return TMF_RESP_FUNC_FAILED; 15889dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas } 15899dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 159024ae163ed33d2b8a70d2f0b1947b401d0a8e8719Jiri Slaby mvi = mvi_dev->mvi_info; 159124ae163ed33d2b8a70d2f0b1947b401d0a8e8719Jiri Slaby 159220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_lock_irqsave(&task->task_state_lock, flags); 159320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->task_state_flags & SAS_TASK_STATE_DONE) { 159420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_unlock_irqrestore(&task->task_state_lock, flags); 159520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = TMF_RESP_FUNC_COMPLETE; 159620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan goto out; 1597dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 159820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_unlock_irqrestore(&task->task_state_lock, flags); 15999dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvi_dev->dev_status = MVS_DEV_EH; 160020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { 160120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task; 160220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 160320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int_to_scsilun(cmnd->device->lun, &lun); 160420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = mvs_find_tag(mvi, task, &tag); 160520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (rc == 0) { 160620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("No such tag in %s\n", __func__); 160720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = TMF_RESP_FUNC_FAILED; 160820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return rc; 160920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 16108f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 161120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmf_task.tmf = TMF_ABORT_TASK; 161220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); 16138f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 161420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task); 16158f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 161620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* if successful, clear the task and callback forwards.*/ 161720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (rc == TMF_RESP_FUNC_COMPLETE) { 161820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 slot_no; 161920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_slot_info *slot; 16208f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 162120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->lldd_task) { 1622f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan slot = task->lldd_task; 162320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan slot_no = (u32) (slot - mvi->slot_info); 16249dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas spin_lock_irqsave(&mvi->lock, flags); 162520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_slot_complete(mvi, slot_no, 1); 16269dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas spin_unlock_irqrestore(&mvi->lock, flags); 162720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 162820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 16299dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 163020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else if (task->task_proto & SAS_PROTOCOL_SATA || 163120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_proto & SAS_PROTOCOL_STP) { 16329dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (SATA_DEV == dev->dev_type) { 16339dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas struct mvs_slot_info *slot = task->lldd_task; 16349dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas u32 slot_idx = (u32)(slot - mvi->slot_info); 163584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mv_dprintk("mvs_abort_task() mvi=%p task=%p " 16369dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas "slot=%p slot_idx=x%x\n", 16379dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvi, task, slot, slot_idx); 163884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mvs_tmf_timedout((unsigned long)task); 16399dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvs_slot_task_free(mvi, task, slot, slot_idx); 164084fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu rc = TMF_RESP_FUNC_COMPLETE; 164184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu goto out; 16429dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas } 16438f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 164420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 164520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanout: 164620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (rc != TMF_RESP_FUNC_COMPLETE) 164720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("%s:rc= %d\n", __func__, rc); 1648dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik return rc; 16498f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 16508f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 165120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_abort_task_set(struct domain_device *dev, u8 *lun) 16528f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 165320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int rc = TMF_RESP_FUNC_FAILED; 165420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_tmf_task tmf_task; 16558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 165620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmf_task.tmf = TMF_ABORT_TASK_SET; 165720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); 1658dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 165920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return rc; 16608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 16618f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 166220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_clear_aca(struct domain_device *dev, u8 *lun) 16638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 166420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int rc = TMF_RESP_FUNC_FAILED; 166520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_tmf_task tmf_task; 16668f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 166720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmf_task.tmf = TMF_CLEAR_ACA; 166820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); 16698f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 167020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return rc; 167120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 16728f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 167320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_clear_task_set(struct domain_device *dev, u8 *lun) 167420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 167520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int rc = TMF_RESP_FUNC_FAILED; 167620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_tmf_task tmf_task; 16778f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 167820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmf_task.tmf = TMF_CLEAR_TASK_SET; 167920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); 16808f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 168120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return rc; 1682dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik} 16838f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 168420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, 168520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 slot_idx, int err) 1686dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik{ 1687f9da3be5afc08c40e7f7a395c8935d500a6898b1Andy Yan struct mvs_device *mvi_dev = task->dev->lldd_dev; 168820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct task_status_struct *tstat = &task->task_status; 168920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; 1690df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley int stat = SAM_STAT_GOOD; 1691e9ff91b6927079307b5d481a93beac4134e923ebKe Wei 16928f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 169320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan resp->frame_len = sizeof(struct dev_to_host_fis); 169420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memcpy(&resp->ending_fis[0], 169520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset), 169620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sizeof(struct dev_to_host_fis)); 169720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tstat->buf_valid_size = sizeof(*resp); 16989dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (unlikely(err)) { 16999dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (unlikely(err & CMD_ISS_STPD)) 17009dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas stat = SAS_OPEN_REJECT; 17019dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas else 17029dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas stat = SAS_PROTO_RESPONSE; 17039dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas } 17049dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 170520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return stat; 17068f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei} 17078f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 1708a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yuvoid mvs_set_sense(u8 *buffer, int len, int d_sense, 1709a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu int key, int asc, int ascq) 1710a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu{ 1711a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu memset(buffer, 0, len); 1712a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu 1713a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (d_sense) { 1714a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu /* Descriptor format */ 1715a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (len < 4) { 1716a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu mv_printk("Length %d of sense buffer too small to " 1717a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu "fit sense %x:%x:%x", len, key, asc, ascq); 1718a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu } 1719a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu 1720a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu buffer[0] = 0x72; /* Response Code */ 1721a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (len > 1) 1722a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu buffer[1] = key; /* Sense Key */ 1723a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (len > 2) 1724a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu buffer[2] = asc; /* ASC */ 1725a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (len > 3) 1726a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu buffer[3] = ascq; /* ASCQ */ 1727a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu } else { 1728a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (len < 14) { 1729a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu mv_printk("Length %d of sense buffer too small to " 1730a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu "fit sense %x:%x:%x", len, key, asc, ascq); 1731a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu } 1732a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu 1733a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu buffer[0] = 0x70; /* Response Code */ 1734a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (len > 2) 1735a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu buffer[2] = key; /* Sense Key */ 1736a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (len > 7) 1737a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu buffer[7] = 0x0a; /* Additional Sense Length */ 1738a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (len > 12) 1739a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu buffer[12] = asc; /* ASC */ 1740a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (len > 13) 1741a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu buffer[13] = ascq; /* ASCQ */ 1742a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu } 1743a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu 1744a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu return; 1745a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu} 1746a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu 1747a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yuvoid mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu, 1748a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu u8 key, u8 asc, u8 asc_q) 1749a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu{ 1750a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu iu->datapres = 2; 1751a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu iu->response_data_len = 0; 1752a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu iu->sense_data_len = 17; 1753a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu iu->status = 02; 1754a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu mvs_set_sense(iu->sense_data, 17, 0, 1755a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu key, asc, asc_q); 1756a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu} 1757a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu 175820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, 175920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 slot_idx) 17608f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei{ 176120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; 176220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int stat; 176384fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu u32 err_dw0 = le32_to_cpu(*(u32 *)slot->response); 1764a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1)); 176520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 tfs = 0; 176620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan enum mvs_port_type type = PORT_TYPE_SAS; 17678f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 176820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (err_dw0 & CMD_ISS_STPD) 176920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->issue_stop(mvi, type, tfs); 177020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 177120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->command_active(mvi, slot_idx); 1772b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1773df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley stat = SAM_STAT_CHECK_CONDITION; 1774dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik switch (task->task_proto) { 1775dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SSP: 1776a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu { 177720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan stat = SAS_ABORTED_TASK; 1778a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if ((err_dw0 & NO_DEST) || err_dw1 & bit(31)) { 1779a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu struct ssp_response_iu *iu = slot->response + 1780a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu sizeof(struct mvs_err_info); 1781a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu mvs_fill_ssp_resp_iu(iu, NOT_READY, 0x04, 01); 1782a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu sas_ssp_task_response(mvi->dev, task, iu); 1783a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu stat = SAM_STAT_CHECK_CONDITION; 1784a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu } 1785a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu if (err_dw1 & bit(31)) 1786a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu mv_printk("reuse same slot, retry command.\n"); 178720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 1788a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu } 178920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case SAS_PROTOCOL_SMP: 1790df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley stat = SAM_STAT_CHECK_CONDITION; 1791dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 179220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 1793dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_SATA: 1794dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik case SAS_PROTOCOL_STP: 179520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: 179620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan { 179720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->ata_task.use_ncq = 0; 179884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu stat = SAS_PROTO_RESPONSE; 17999dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvs_sata_done(mvi, task, slot_idx, err_dw0); 1800dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 180120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 1802dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik default: 1803dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik break; 1804dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik } 1805dd4969a892ea522ecf9d7d826ba1531ce044d46fJeff Garzik 180620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return stat; 1807e9ff91b6927079307b5d481a93beac4134e923ebKe Wei} 1808e9ff91b6927079307b5d481a93beac4134e923ebKe Wei 180920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) 1810b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 181120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 slot_idx = rx_desc & RXQ_SLOT_MASK; 181220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; 181320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_task *task = slot->task; 181420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_device *mvi_dev = NULL; 181520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct task_status_struct *tstat; 18169dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas struct domain_device *dev; 18179dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas u32 aborted; 181820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 181920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan void *to; 182020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan enum exec_status sts; 182120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 18229dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (unlikely(!task || !task->lldd_task || !task->dev)) 182320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return -1; 182420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 182520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tstat = &task->task_status; 18269dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas dev = task->dev; 18279dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvi_dev = dev->lldd_dev; 1828b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 182920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_lock(&task->task_state_lock); 183020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_state_flags &= 183120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); 183220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_state_flags |= SAS_TASK_STATE_DONE; 183320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* race condition*/ 183420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; 183520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_unlock(&task->task_state_lock); 183620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 183720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memset(tstat, 0, sizeof(*tstat)); 183820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tstat->resp = SAS_TASK_COMPLETE; 183920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 184020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (unlikely(aborted)) { 184120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tstat->stat = SAS_ABORTED_TASK; 18429dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (mvi_dev && mvi_dev->running_req) 18439dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvi_dev->running_req--; 184420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (sas_protocol_ata(task->task_proto)) 184520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_free_reg_set(mvi, mvi_dev); 184620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 184720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_slot_task_free(mvi, task, slot, slot_idx); 184820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return -1; 1849b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1850b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 1851e144f7ef49ec85e9dfdf130f3a9a2372fe5fe39bXiangliang Yu /* when no device attaching, go ahead and complete by error handling*/ 18529dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (unlikely(!mvi_dev || flags)) { 18539dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (!mvi_dev) 18549dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mv_dprintk("port has not device.\n"); 185520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tstat->stat = SAS_PHY_DOWN; 185620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan goto out; 185720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 1858b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 185920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* error info record present */ 186020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) { 186184fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mv_dprintk("port %d slot %d rx_desc %X has error info" 186284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu "%016llX.\n", slot->port->sas_port.id, slot_idx, 186384fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu rx_desc, (u64)(*(u64 *)slot->response)); 186420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tstat->stat = mvs_slot_err(mvi, task, slot_idx); 18659dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas tstat->resp = SAS_TASK_COMPLETE; 186620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan goto out; 1867b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 1868b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 186920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan switch (task->task_proto) { 187020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case SAS_PROTOCOL_SSP: 187120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* hw says status == 0, datapres == 0 */ 187220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (rx_desc & RXQ_GOOD) { 1873df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley tstat->stat = SAM_STAT_GOOD; 187420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tstat->resp = SAS_TASK_COMPLETE; 187520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 187620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* response frame present */ 187720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan else if (rx_desc & RXQ_RSP) { 187820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct ssp_response_iu *iu = slot->response + 187920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sizeof(struct mvs_err_info); 188020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sas_ssp_task_response(mvi->dev, task, iu); 188120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else 1882df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley tstat->stat = SAM_STAT_CHECK_CONDITION; 188320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 1884b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 188520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case SAS_PROTOCOL_SMP: { 188620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct scatterlist *sg_resp = &task->smp_task.smp_resp; 1887df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley tstat->stat = SAM_STAT_GOOD; 188820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan to = kmap_atomic(sg_page(sg_resp), KM_IRQ0); 188920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan memcpy(to + sg_resp->offset, 189020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan slot->response + sizeof(struct mvs_err_info), 189120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sg_dma_len(sg_resp)); 189220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan kunmap_atomic(to, KM_IRQ0); 189320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 189420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 18958f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 189620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case SAS_PROTOCOL_SATA: 189720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case SAS_PROTOCOL_STP: 189820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { 189920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0); 190020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 190120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 1902b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 190320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan default: 1904df64d3caab8db6ae17dacd229a03d7689a10c432James Bottomley tstat->stat = SAM_STAT_CHECK_CONDITION; 190520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan break; 190620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 19079dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (!slot->port->port_attached) { 19089dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mv_dprintk("port %d has removed.\n", slot->port->sas_port.id); 19099dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas tstat->stat = SAS_PHY_DOWN; 19109dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas } 19119dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 1912b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 191320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanout: 19149dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (mvi_dev && mvi_dev->running_req) { 19159dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvi_dev->running_req--; 19169dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (sas_protocol_ata(task->task_proto) && !mvi_dev->running_req) 19170f980a871678b7ec143fcb45b31bf9234e4585c8Andy Yan mvs_free_reg_set(mvi, mvi_dev); 19180f980a871678b7ec143fcb45b31bf9234e4585c8Andy Yan } 191920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_slot_task_free(mvi, task, slot, slot_idx); 192020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sts = tstat->stat; 19218f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 192220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_unlock(&mvi->lock); 192320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (task->task_done) 192420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task->task_done(task); 192584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu 192620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_lock(&mvi->lock); 1927b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 192820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return sts; 192920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 1930b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 19319dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivasvoid mvs_do_release_task(struct mvs_info *mvi, 193220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int phy_no, struct domain_device *dev) 193320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 19349dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas u32 slot_idx; 193520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_phy *phy; 193620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_port *port; 193720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_slot_info *slot, *slot2; 1938b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 193920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy = &mvi->phy[phy_no]; 194020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan port = phy->port; 194120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!port) 194220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return; 19439dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas /* clean cmpl queue in case request is already finished */ 19449dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvs_int_rx(mvi, false); 19459dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 19469dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 1947b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 194820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan list_for_each_entry_safe(slot, slot2, &port->list, entry) { 194920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_task *task; 195020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan slot_idx = (u32) (slot - mvi->slot_info); 195120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan task = slot->task; 1952b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 195320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (dev && task->dev != dev) 195420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan continue; 19558f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 195620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_printk("Release slot [%x] tag[%x], task [%p]:\n", 195720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan slot_idx, slot->slot_tag, task); 19589dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas MVS_CHIP_DISP->command_active(mvi, slot_idx); 1959b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 196020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_slot_complete(mvi, slot_idx, 1); 1961b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 196220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 1963b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 19649dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivasvoid mvs_release_task(struct mvs_info *mvi, 19659dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas struct domain_device *dev) 19669dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas{ 19679dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas int i, phyno[WIDE_PORT_MAX_PHY], num; 19689dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas num = mvs_find_dev_phyno(dev, phyno); 19699dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas for (i = 0; i < num; i++) 19709dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvs_do_release_task(mvi, phyno[i], dev); 19719dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas} 19729dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 197320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_phy_disconnected(struct mvs_phy *phy) 197420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 197520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->phy_attached = 0; 197620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->att_dev_info = 0; 197720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->att_dev_sas_addr = 0; 197820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 197920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 198020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_work_queue(struct work_struct *work) 198120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 198220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct delayed_work *dw = container_of(work, struct delayed_work, work); 198320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q); 198420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_info *mvi = mwq->mvi; 198520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan unsigned long flags; 1986a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu u32 phy_no = (unsigned long) mwq->data; 1987a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu struct sas_ha_struct *sas_ha = mvi->sas; 1988a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu struct mvs_phy *phy = &mvi->phy[phy_no]; 1989a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu struct asd_sas_phy *sas_phy = &phy->sas_phy; 1990b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 199120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_lock_irqsave(&mvi->lock, flags); 199220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mwq->handler & PHY_PLUG_EVENT) { 199320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 199420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy->phy_event & PHY_PLUG_OUT) { 199520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 tmp; 199620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct sas_identify_frame *id; 199720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan id = (struct sas_identify_frame *)phy->frame_rcvd; 199820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no); 199920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->phy_event &= ~PHY_PLUG_OUT; 200020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!(tmp & PHY_READY_MASK)) { 200120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sas_phy_disconnected(sas_phy); 200220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_phy_disconnected(phy); 200320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan sas_ha->notify_phy_event(sas_phy, 200420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan PHYE_LOSS_OF_SIGNAL); 200520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("phy%d Removed Device\n", phy_no); 200620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else { 200720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->detect_porttype(mvi, phy_no); 200820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_update_phyinfo(mvi, phy_no, 1); 200920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_bytes_dmaed(mvi, phy_no); 201020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_port_notify_formed(sas_phy, 0); 201120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("phy%d Attached Device\n", phy_no); 201220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 201320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 2014a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu } else if (mwq->handler & EXP_BRCT_CHG) { 2015a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu phy->phy_event &= ~EXP_BRCT_CHG; 2016a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu sas_ha->notify_port_event(sas_phy, 2017a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu PORTE_BROADCAST_RCVD); 2018a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu mv_dprintk("phy%d Got Broadcast Change\n", phy_no); 201920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 202020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan list_del(&mwq->entry); 202120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan spin_unlock_irqrestore(&mvi->lock, flags); 202220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan kfree(mwq); 202320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 20248f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 202520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic int mvs_handle_event(struct mvs_info *mvi, void *data, int handler) 202620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 202720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_wq *mwq; 202820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int ret = 0; 202920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 203020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC); 203120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mwq) { 203220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mwq->mvi = mvi; 203320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mwq->data = data; 203420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mwq->handler = handler; 203520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq); 203620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan list_add_tail(&mwq->entry, &mvi->wq_list); 203720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan schedule_delayed_work(&mwq->work_q, HZ * 2); 203820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else 203920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan ret = -ENOMEM; 204020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 204120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return ret; 204220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 2043b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 204420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanstatic void mvs_sig_time_out(unsigned long tphy) 204520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 204620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_phy *phy = (struct mvs_phy *)tphy; 204720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_info *mvi = phy->mvi; 204820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u8 phy_no; 204920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 205020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan for (phy_no = 0; phy_no < mvi->chip->n_phy; phy_no++) { 205120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (&mvi->phy[phy_no] == phy) { 205220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("Get signature time out, reset phy %d\n", 205320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy_no+mvi->id*mvi->chip->n_phy); 2054a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_HARD_RESET); 205520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 2056b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik } 205720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan} 2058b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 205920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanvoid mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) 206020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan{ 206120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 tmp; 206220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan struct mvs_phy *phy = &mvi->phy[phy_no]; 20638f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 206420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no); 206584fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status); 206684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mv_dprintk("phy %d ctrl sts=0x%08X.\n", phy_no+mvi->id*mvi->chip->n_phy, 206720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no)); 206884fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mv_dprintk("phy %d irq sts = 0x%08X\n", phy_no+mvi->id*mvi->chip->n_phy, 206920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->irq_status); 20708f261aaf9be5c1246013cf6a65b98586d24832a5Ke Wei 207120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* 207220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * events is port event now , 207320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * we need check the interrupt status which belongs to per port. 207420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan */ 2075b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 20769dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (phy->irq_status & PHYEV_DCDR_ERR) { 207784fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mv_dprintk("phy %d STP decoding error.\n", 20789dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas phy_no + mvi->id*mvi->chip->n_phy); 20799dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas } 208020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 208120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy->irq_status & PHYEV_POOF) { 208284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mdelay(500); 208320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!(phy->phy_event & PHY_PLUG_OUT)) { 208420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int dev_sata = phy->phy_type & PORT_TYPE_SATA; 208520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan int ready; 20869dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mvs_do_release_task(mvi, phy_no, NULL); 208720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->phy_event |= PHY_PLUG_OUT; 20889dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas MVS_CHIP_DISP->clear_srs_irq(mvi, 0, 1); 208920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_handle_event(mvi, 209020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan (void *)(unsigned long)phy_no, 209120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan PHY_PLUG_EVENT); 209220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan ready = mvs_is_phy_ready(mvi, phy_no); 209320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (ready || dev_sata) { 209420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (MVS_CHIP_DISP->stp_reset) 209520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->stp_reset(mvi, 209620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy_no); 209720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan else 209820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->phy_reset(mvi, 2099a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu phy_no, MVS_SOFT_RESET); 210020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return; 210120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 210220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 210320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 2104b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 210520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy->irq_status & PHYEV_COMWAKE) { 210620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, phy_no); 210720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no, 210820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmp | PHYEV_SIG_FIS); 210920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy->timer.function == NULL) { 211020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->timer.data = (unsigned long)phy; 211120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->timer.function = mvs_sig_time_out; 211284fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu phy->timer.expires = jiffies + 5*HZ; 211320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan add_timer(&phy->timer); 211420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 211520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 211620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) { 211720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->phy_status = mvs_is_phy_ready(mvi, phy_no); 211820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("notify plug in on phy[%d]\n", phy_no); 211920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy->phy_status) { 212020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mdelay(10); 212120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->detect_porttype(mvi, phy_no); 212220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy->phy_type & PORT_TYPE_SATA) { 212320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmp = MVS_CHIP_DISP->read_port_irq_mask( 212420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi, phy_no); 212520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan tmp &= ~PHYEV_SIG_FIS; 212620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->write_port_irq_mask(mvi, 212720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy_no, tmp); 212820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 212920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_update_phyinfo(mvi, phy_no, 0); 21309dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas if (phy->phy_type & PORT_TYPE_SAS) { 2131a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_PHY_TUNE); 21329dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas mdelay(10); 21339dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas } 21349dc9fd9484c5168d23fe855e6c56543d96b6695bSrinivas 213520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_bytes_dmaed(mvi, phy_no); 213620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* whether driver is going to handle hot plug */ 213720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (phy->phy_event & PHY_PLUG_OUT) { 2138a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu mvs_port_notify_formed(&phy->sas_phy, 0); 213920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy->phy_event &= ~PHY_PLUG_OUT; 214020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 214120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else { 214220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mv_dprintk("plugin interrupt but phy%d is gone\n", 214320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy_no + mvi->id*mvi->chip->n_phy); 214420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 214520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else if (phy->irq_status & PHYEV_BROAD_CH) { 214684fbd0cea11b80d7b7097343d5262004d42b8a9aXiangliang Yu mv_dprintk("phy %d broadcast change.\n", 214720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan phy_no + mvi->id*mvi->chip->n_phy); 2148a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu mvs_handle_event(mvi, (void *)(unsigned long)phy_no, 2149a4632aae8b662b1f32fe3fc558a813cd5c3daae6Xiangliang Yu EXP_BRCT_CHG); 215020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 2151b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 2152b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 215320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yanint mvs_int_rx(struct mvs_info *mvi, bool self_clear) 2154b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik{ 215520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan u32 rx_prod_idx, rx_desc; 215620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan bool attn = false; 2157b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 215820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* the first dword in the RX ring is special: it contains 215920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * a mirror of the hardware's RX producer index, so that 216020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * we don't have to stall the CPU reading that register. 216120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * The actual RX ring is offset by one dword, due to this. 216220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan */ 216320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rx_prod_idx = mvi->rx_cons; 216420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi->rx_cons = le32_to_cpu(mvi->rx[0]); 216520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvi->rx_cons == 0xfff) /* h/w hasn't touched RX ring yet */ 216620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return 0; 2167b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 216820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* The CMPL_Q may come late, read from register and try again 216920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * note: if coalescing is enabled, 217020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan * it will need to read from register every time for sure 217120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan */ 217220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (unlikely(mvi->rx_cons == rx_prod_idx)) 217320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvi->rx_cons = MVS_CHIP_DISP->rx_update(mvi) & RX_RING_SZ_MASK; 217420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 217520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (mvi->rx_cons == rx_prod_idx) 217620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return 0; 217720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 217820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan while (mvi->rx_cons != rx_prod_idx) { 217920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan /* increment our internal RX consumer pointer */ 218020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1); 218120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]); 218220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 218320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (likely(rx_desc & RXQ_DONE)) 218420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_slot_complete(mvi, rx_desc, 0); 218520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (rx_desc & RXQ_ATTN) { 218620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan attn = true; 218720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else if (rx_desc & RXQ_ERR) { 218820b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (!(rx_desc & RXQ_DONE)) 218920b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_slot_complete(mvi, rx_desc, 0); 219020b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } else if (rx_desc & RXQ_SLOT_RESET) { 219120b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan mvs_slot_free(mvi, rx_desc); 219220b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 219320b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan } 219420b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan 219520b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan if (attn && self_clear) 219620b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan MVS_CHIP_DISP->int_full(mvi); 219720b09c2992fefbe78f8cede7b404fb143a413c52Andy Yan return 0; 2198b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik} 2199b5762948263dd5e9725a380e7a9626f99e40ae9dJeff Garzik 2200