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 332908d778SJames Bottomley static void sas_phye_loss_of_signal(void *data) 342908d778SJames Bottomley { 352908d778SJames Bottomley struct asd_sas_phy *phy = data; 362908d778SJames Bottomley 372908d778SJames Bottomley sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock, 382908d778SJames Bottomley &phy->phy_events_pending); 392908d778SJames Bottomley phy->error = 0; 402908d778SJames Bottomley sas_deform_port(phy); 412908d778SJames Bottomley } 422908d778SJames Bottomley 432908d778SJames Bottomley static void sas_phye_oob_done(void *data) 442908d778SJames Bottomley { 452908d778SJames Bottomley struct asd_sas_phy *phy = data; 462908d778SJames Bottomley 472908d778SJames Bottomley sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock, 482908d778SJames Bottomley &phy->phy_events_pending); 492908d778SJames Bottomley phy->error = 0; 502908d778SJames Bottomley } 512908d778SJames Bottomley 522908d778SJames Bottomley static void sas_phye_oob_error(void *data) 532908d778SJames Bottomley { 542908d778SJames Bottomley struct asd_sas_phy *phy = data; 552908d778SJames Bottomley struct sas_ha_struct *sas_ha = phy->ha; 562908d778SJames Bottomley struct asd_sas_port *port = phy->port; 572908d778SJames Bottomley struct sas_internal *i = 582908d778SJames Bottomley to_sas_internal(sas_ha->core.shost->transportt); 592908d778SJames Bottomley 602908d778SJames Bottomley sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock, 612908d778SJames Bottomley &phy->phy_events_pending); 622908d778SJames Bottomley 632908d778SJames Bottomley sas_deform_port(phy); 642908d778SJames Bottomley 652908d778SJames Bottomley if (!port && phy->enabled && i->dft->lldd_control_phy) { 662908d778SJames Bottomley phy->error++; 672908d778SJames Bottomley switch (phy->error) { 682908d778SJames Bottomley case 1: 692908d778SJames Bottomley case 2: 70a01e70e5SJames Bottomley i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET, 71a01e70e5SJames Bottomley NULL); 722908d778SJames Bottomley break; 732908d778SJames Bottomley case 3: 742908d778SJames Bottomley default: 752908d778SJames Bottomley phy->error = 0; 762908d778SJames Bottomley phy->enabled = 0; 77a01e70e5SJames Bottomley i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL); 782908d778SJames Bottomley break; 792908d778SJames Bottomley } 802908d778SJames Bottomley } 812908d778SJames Bottomley } 822908d778SJames Bottomley 832908d778SJames Bottomley static void sas_phye_spinup_hold(void *data) 842908d778SJames Bottomley { 852908d778SJames Bottomley struct asd_sas_phy *phy = data; 862908d778SJames Bottomley struct sas_ha_struct *sas_ha = phy->ha; 872908d778SJames Bottomley struct sas_internal *i = 882908d778SJames Bottomley to_sas_internal(sas_ha->core.shost->transportt); 892908d778SJames Bottomley 902908d778SJames Bottomley sas_begin_event(PHYE_SPINUP_HOLD, &phy->ha->event_lock, 912908d778SJames Bottomley &phy->phy_events_pending); 922908d778SJames Bottomley 932908d778SJames Bottomley phy->error = 0; 94a01e70e5SJames Bottomley i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL); 952908d778SJames Bottomley } 962908d778SJames Bottomley 972908d778SJames Bottomley /* ---------- Phy class registration ---------- */ 982908d778SJames Bottomley 992908d778SJames Bottomley int sas_register_phys(struct sas_ha_struct *sas_ha) 1002908d778SJames Bottomley { 1012908d778SJames Bottomley int i; 1022908d778SJames Bottomley 1032908d778SJames Bottomley static void (*sas_phy_event_fns[PHY_NUM_EVENTS])(void *) = { 1042908d778SJames Bottomley [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal, 1052908d778SJames Bottomley [PHYE_OOB_DONE] = sas_phye_oob_done, 1062908d778SJames Bottomley [PHYE_OOB_ERROR] = sas_phye_oob_error, 1072908d778SJames Bottomley [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold, 1082908d778SJames Bottomley }; 1092908d778SJames Bottomley 1102908d778SJames Bottomley static void (*sas_port_event_fns[PORT_NUM_EVENTS])(void *) = { 1112908d778SJames Bottomley [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed, 1122908d778SJames Bottomley [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd, 1132908d778SJames Bottomley [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err, 1142908d778SJames Bottomley [PORTE_TIMER_EVENT] = sas_porte_timer_event, 1152908d778SJames Bottomley [PORTE_HARD_RESET] = sas_porte_hard_reset, 1162908d778SJames Bottomley }; 1172908d778SJames Bottomley 1182908d778SJames Bottomley /* Now register the phys. */ 1192908d778SJames Bottomley for (i = 0; i < sas_ha->num_phys; i++) { 1202908d778SJames Bottomley int k; 1212908d778SJames Bottomley struct asd_sas_phy *phy = sas_ha->sas_phy[i]; 1222908d778SJames Bottomley 1232908d778SJames Bottomley phy->error = 0; 1242908d778SJames Bottomley INIT_LIST_HEAD(&phy->port_phy_el); 1252908d778SJames Bottomley for (k = 0; k < PORT_NUM_EVENTS; k++) 1262908d778SJames Bottomley INIT_WORK(&phy->port_events[k], sas_port_event_fns[k], 1272908d778SJames Bottomley phy); 1282908d778SJames Bottomley 1292908d778SJames Bottomley for (k = 0; k < PHY_NUM_EVENTS; k++) 1302908d778SJames Bottomley INIT_WORK(&phy->phy_events[k], sas_phy_event_fns[k], 1312908d778SJames Bottomley phy); 1322908d778SJames Bottomley phy->port = NULL; 1332908d778SJames Bottomley phy->ha = sas_ha; 1342908d778SJames Bottomley spin_lock_init(&phy->frame_rcvd_lock); 1352908d778SJames Bottomley spin_lock_init(&phy->sas_prim_lock); 1362908d778SJames Bottomley phy->frame_rcvd_size = 0; 1372908d778SJames Bottomley 1382908d778SJames Bottomley phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev, 1392908d778SJames Bottomley i); 1402908d778SJames Bottomley if (!phy->phy) 1412908d778SJames Bottomley return -ENOMEM; 1422908d778SJames Bottomley 1432908d778SJames Bottomley phy->phy->identify.initiator_port_protocols = 1442908d778SJames Bottomley phy->iproto; 1452908d778SJames Bottomley phy->phy->identify.target_port_protocols = phy->tproto; 1462908d778SJames Bottomley phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr); 1472908d778SJames Bottomley phy->phy->identify.phy_identifier = i; 148a01e70e5SJames Bottomley phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 149a01e70e5SJames Bottomley phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 150a01e70e5SJames Bottomley phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; 151a01e70e5SJames Bottomley phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; 1522908d778SJames Bottomley phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; 1532908d778SJames Bottomley 1542908d778SJames Bottomley sas_phy_add(phy->phy); 1552908d778SJames Bottomley } 1562908d778SJames Bottomley 1572908d778SJames Bottomley return 0; 1582908d778SJames Bottomley } 159