12908d778SJames Bottomley /* 22908d778SJames Bottomley * Serial Attached SCSI (SAS) Phy class 32908d778SJames Bottomley * 42908d778SJames Bottomley * Copyright (C) 2005 Adaptec, Inc. All rights reserved. 52908d778SJames Bottomley * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> 62908d778SJames Bottomley * 72908d778SJames Bottomley * This file is licensed under GPLv2. 82908d778SJames Bottomley * 92908d778SJames Bottomley * This program is free software; you can redistribute it and/or 102908d778SJames Bottomley * modify it under the terms of the GNU General Public License as 112908d778SJames Bottomley * published by the Free Software Foundation; either version 2 of the 122908d778SJames Bottomley * License, or (at your option) any later version. 132908d778SJames Bottomley * 142908d778SJames Bottomley * This program is distributed in the hope that it will be useful, but 152908d778SJames Bottomley * WITHOUT ANY WARRANTY; without even the implied warranty of 162908d778SJames Bottomley * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 172908d778SJames Bottomley * General Public License for more details. 182908d778SJames Bottomley * 192908d778SJames Bottomley * You should have received a copy of the GNU General Public License 202908d778SJames Bottomley * along with this program; if not, write to the Free Software 212908d778SJames Bottomley * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 222908d778SJames Bottomley * 232908d778SJames Bottomley */ 242908d778SJames Bottomley 252908d778SJames Bottomley #include "sas_internal.h" 262908d778SJames Bottomley #include <scsi/scsi_host.h> 272908d778SJames Bottomley #include <scsi/scsi_transport.h> 282908d778SJames Bottomley #include <scsi/scsi_transport_sas.h> 292908d778SJames Bottomley #include "../scsi_sas_internal.h" 302908d778SJames Bottomley 312908d778SJames Bottomley /* ---------- Phy events ---------- */ 322908d778SJames Bottomley 33c4028958SDavid Howells static void sas_phye_loss_of_signal(struct work_struct *work) 342908d778SJames Bottomley { 3522b9153fSDan Williams struct asd_sas_event *ev = to_asd_sas_event(work); 36c4028958SDavid Howells struct asd_sas_phy *phy = ev->phy; 372908d778SJames Bottomley 38f12486e0SJason Yan phy->in_shutdown = 0; 392908d778SJames Bottomley phy->error = 0; 4090f1e10dSDan Williams sas_deform_port(phy, 1); 412908d778SJames Bottomley } 422908d778SJames Bottomley 43c4028958SDavid Howells static void sas_phye_oob_done(struct work_struct *work) 442908d778SJames Bottomley { 4522b9153fSDan Williams struct asd_sas_event *ev = to_asd_sas_event(work); 46c4028958SDavid Howells struct asd_sas_phy *phy = ev->phy; 472908d778SJames Bottomley 48f12486e0SJason Yan phy->in_shutdown = 0; 492908d778SJames Bottomley phy->error = 0; 502908d778SJames Bottomley } 512908d778SJames Bottomley 52c4028958SDavid Howells static void sas_phye_oob_error(struct work_struct *work) 532908d778SJames Bottomley { 5422b9153fSDan Williams struct asd_sas_event *ev = to_asd_sas_event(work); 55c4028958SDavid Howells struct asd_sas_phy *phy = ev->phy; 562908d778SJames Bottomley struct sas_ha_struct *sas_ha = phy->ha; 572908d778SJames Bottomley struct asd_sas_port *port = phy->port; 582908d778SJames Bottomley struct sas_internal *i = 592908d778SJames Bottomley to_sas_internal(sas_ha->core.shost->transportt); 602908d778SJames Bottomley 6190f1e10dSDan Williams sas_deform_port(phy, 1); 622908d778SJames Bottomley 632908d778SJames Bottomley if (!port && phy->enabled && i->dft->lldd_control_phy) { 642908d778SJames Bottomley phy->error++; 652908d778SJames Bottomley switch (phy->error) { 662908d778SJames Bottomley case 1: 672908d778SJames Bottomley case 2: 68a01e70e5SJames Bottomley i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET, 69a01e70e5SJames Bottomley NULL); 702908d778SJames Bottomley break; 712908d778SJames Bottomley case 3: 722908d778SJames Bottomley default: 732908d778SJames Bottomley phy->error = 0; 742908d778SJames Bottomley phy->enabled = 0; 75a01e70e5SJames Bottomley i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL); 762908d778SJames Bottomley break; 772908d778SJames Bottomley } 782908d778SJames Bottomley } 792908d778SJames Bottomley } 802908d778SJames Bottomley 81c4028958SDavid Howells static void sas_phye_spinup_hold(struct work_struct *work) 822908d778SJames Bottomley { 8322b9153fSDan Williams struct asd_sas_event *ev = to_asd_sas_event(work); 84c4028958SDavid Howells struct asd_sas_phy *phy = ev->phy; 852908d778SJames Bottomley struct sas_ha_struct *sas_ha = phy->ha; 862908d778SJames Bottomley struct sas_internal *i = 872908d778SJames Bottomley to_sas_internal(sas_ha->core.shost->transportt); 882908d778SJames Bottomley 892908d778SJames Bottomley phy->error = 0; 90a01e70e5SJames Bottomley i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL); 912908d778SJames Bottomley } 922908d778SJames Bottomley 93303694eeSDan Williams static void sas_phye_resume_timeout(struct work_struct *work) 94303694eeSDan Williams { 95303694eeSDan Williams struct asd_sas_event *ev = to_asd_sas_event(work); 96303694eeSDan Williams struct asd_sas_phy *phy = ev->phy; 97303694eeSDan Williams 98303694eeSDan Williams /* phew, lldd got the phy back in the nick of time */ 99303694eeSDan Williams if (!phy->suspended) { 100303694eeSDan Williams dev_info(&phy->phy->dev, "resume timeout cancelled\n"); 101303694eeSDan Williams return; 102303694eeSDan Williams } 103303694eeSDan Williams 104303694eeSDan Williams phy->error = 0; 105303694eeSDan Williams phy->suspended = 0; 106303694eeSDan Williams sas_deform_port(phy, 1); 107303694eeSDan Williams } 108303694eeSDan Williams 109303694eeSDan Williams 110f12486e0SJason Yan static void sas_phye_shutdown(struct work_struct *work) 111f12486e0SJason Yan { 112f12486e0SJason Yan struct asd_sas_event *ev = to_asd_sas_event(work); 113f12486e0SJason Yan struct asd_sas_phy *phy = ev->phy; 114f12486e0SJason Yan struct sas_ha_struct *sas_ha = phy->ha; 115f12486e0SJason Yan struct sas_internal *i = 116f12486e0SJason Yan to_sas_internal(sas_ha->core.shost->transportt); 117f12486e0SJason Yan 118f12486e0SJason Yan if (phy->enabled) { 119f12486e0SJason Yan int ret; 120f12486e0SJason Yan 121f12486e0SJason Yan phy->error = 0; 122f12486e0SJason Yan phy->enabled = 0; 123f12486e0SJason Yan ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL); 124f12486e0SJason Yan if (ret) 1253c236f8cSJohn Garry pr_notice("lldd disable phy%d returned %d\n", phy->id, 1263c236f8cSJohn Garry ret); 127f12486e0SJason Yan } else 1283c236f8cSJohn Garry pr_notice("phy%d is not enabled, cannot shutdown\n", phy->id); 129f12486e0SJason Yan } 130f12486e0SJason Yan 1312908d778SJames Bottomley /* ---------- Phy class registration ---------- */ 1322908d778SJames Bottomley 1332908d778SJames Bottomley int sas_register_phys(struct sas_ha_struct *sas_ha) 1342908d778SJames Bottomley { 1352908d778SJames Bottomley int i; 1362908d778SJames Bottomley 1372908d778SJames Bottomley /* Now register the phys. */ 1382908d778SJames Bottomley for (i = 0; i < sas_ha->num_phys; i++) { 1392908d778SJames Bottomley struct asd_sas_phy *phy = sas_ha->sas_phy[i]; 1402908d778SJames Bottomley 1412908d778SJames Bottomley phy->error = 0; 142f12486e0SJason Yan atomic_set(&phy->event_nr, 0); 1432908d778SJames Bottomley INIT_LIST_HEAD(&phy->port_phy_el); 144c4028958SDavid Howells 1452908d778SJames Bottomley phy->port = NULL; 1462908d778SJames Bottomley phy->ha = sas_ha; 1472908d778SJames Bottomley spin_lock_init(&phy->frame_rcvd_lock); 1482908d778SJames Bottomley spin_lock_init(&phy->sas_prim_lock); 1492908d778SJames Bottomley phy->frame_rcvd_size = 0; 1502908d778SJames Bottomley 15122b9153fSDan Williams phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev, i); 1522908d778SJames Bottomley if (!phy->phy) 1532908d778SJames Bottomley return -ENOMEM; 1542908d778SJames Bottomley 1552908d778SJames Bottomley phy->phy->identify.initiator_port_protocols = 1562908d778SJames Bottomley phy->iproto; 1572908d778SJames Bottomley phy->phy->identify.target_port_protocols = phy->tproto; 1582908d778SJames Bottomley phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr); 1592908d778SJames Bottomley phy->phy->identify.phy_identifier = i; 160a01e70e5SJames Bottomley phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 161a01e70e5SJames Bottomley phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 162a01e70e5SJames Bottomley phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; 163a01e70e5SJames Bottomley phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; 1642908d778SJames Bottomley phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; 1652908d778SJames Bottomley 1662908d778SJames Bottomley sas_phy_add(phy->phy); 1672908d778SJames Bottomley } 1682908d778SJames Bottomley 1692908d778SJames Bottomley return 0; 1702908d778SJames Bottomley } 1711c393b97SJason Yan 1721c393b97SJason Yan const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = { 1731c393b97SJason Yan [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal, 1741c393b97SJason Yan [PHYE_OOB_DONE] = sas_phye_oob_done, 1751c393b97SJason Yan [PHYE_OOB_ERROR] = sas_phye_oob_error, 1761c393b97SJason Yan [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold, 1771c393b97SJason Yan [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout, 178f12486e0SJason Yan [PHYE_SHUTDOWN] = sas_phye_shutdown, 1791c393b97SJason Yan }; 180