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 { 35c4028958SDavid Howells struct asd_sas_event *ev = 36c4028958SDavid Howells container_of(work, struct asd_sas_event, work); 37c4028958SDavid Howells struct asd_sas_phy *phy = ev->phy; 382908d778SJames Bottomley 392908d778SJames Bottomley sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock, 402908d778SJames Bottomley &phy->phy_events_pending); 412908d778SJames Bottomley phy->error = 0; 422908d778SJames Bottomley sas_deform_port(phy); 432908d778SJames Bottomley } 442908d778SJames Bottomley 45c4028958SDavid Howells static void sas_phye_oob_done(struct work_struct *work) 462908d778SJames Bottomley { 47c4028958SDavid Howells struct asd_sas_event *ev = 48c4028958SDavid Howells container_of(work, struct asd_sas_event, work); 49c4028958SDavid Howells struct asd_sas_phy *phy = ev->phy; 502908d778SJames Bottomley 512908d778SJames Bottomley sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock, 522908d778SJames Bottomley &phy->phy_events_pending); 532908d778SJames Bottomley phy->error = 0; 542908d778SJames Bottomley } 552908d778SJames Bottomley 56c4028958SDavid Howells static void sas_phye_oob_error(struct work_struct *work) 572908d778SJames Bottomley { 58c4028958SDavid Howells struct asd_sas_event *ev = 59c4028958SDavid Howells container_of(work, struct asd_sas_event, work); 60c4028958SDavid Howells struct asd_sas_phy *phy = ev->phy; 612908d778SJames Bottomley struct sas_ha_struct *sas_ha = phy->ha; 622908d778SJames Bottomley struct asd_sas_port *port = phy->port; 632908d778SJames Bottomley struct sas_internal *i = 642908d778SJames Bottomley to_sas_internal(sas_ha->core.shost->transportt); 652908d778SJames Bottomley 662908d778SJames Bottomley sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock, 672908d778SJames Bottomley &phy->phy_events_pending); 682908d778SJames Bottomley 692908d778SJames Bottomley sas_deform_port(phy); 702908d778SJames Bottomley 712908d778SJames Bottomley if (!port && phy->enabled && i->dft->lldd_control_phy) { 722908d778SJames Bottomley phy->error++; 732908d778SJames Bottomley switch (phy->error) { 742908d778SJames Bottomley case 1: 752908d778SJames Bottomley case 2: 76a01e70e5SJames Bottomley i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET, 77a01e70e5SJames Bottomley NULL); 782908d778SJames Bottomley break; 792908d778SJames Bottomley case 3: 802908d778SJames Bottomley default: 812908d778SJames Bottomley phy->error = 0; 822908d778SJames Bottomley phy->enabled = 0; 83a01e70e5SJames Bottomley i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL); 842908d778SJames Bottomley break; 852908d778SJames Bottomley } 862908d778SJames Bottomley } 872908d778SJames Bottomley } 882908d778SJames Bottomley 89c4028958SDavid Howells static void sas_phye_spinup_hold(struct work_struct *work) 902908d778SJames Bottomley { 91c4028958SDavid Howells struct asd_sas_event *ev = 92c4028958SDavid Howells container_of(work, struct asd_sas_event, work); 93c4028958SDavid Howells struct asd_sas_phy *phy = ev->phy; 942908d778SJames Bottomley struct sas_ha_struct *sas_ha = phy->ha; 952908d778SJames Bottomley struct sas_internal *i = 962908d778SJames Bottomley to_sas_internal(sas_ha->core.shost->transportt); 972908d778SJames Bottomley 982908d778SJames Bottomley sas_begin_event(PHYE_SPINUP_HOLD, &phy->ha->event_lock, 992908d778SJames Bottomley &phy->phy_events_pending); 1002908d778SJames Bottomley 1012908d778SJames Bottomley phy->error = 0; 102a01e70e5SJames Bottomley i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL); 1032908d778SJames Bottomley } 1042908d778SJames Bottomley 1052908d778SJames Bottomley /* ---------- Phy class registration ---------- */ 1062908d778SJames Bottomley 1072908d778SJames Bottomley int sas_register_phys(struct sas_ha_struct *sas_ha) 1082908d778SJames Bottomley { 1092908d778SJames Bottomley int i; 1102908d778SJames Bottomley 111c4028958SDavid Howells static const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = { 1122908d778SJames Bottomley [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal, 1132908d778SJames Bottomley [PHYE_OOB_DONE] = sas_phye_oob_done, 1142908d778SJames Bottomley [PHYE_OOB_ERROR] = sas_phye_oob_error, 1152908d778SJames Bottomley [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold, 1162908d778SJames Bottomley }; 1172908d778SJames Bottomley 118c4028958SDavid Howells static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = { 1192908d778SJames Bottomley [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed, 1202908d778SJames Bottomley [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd, 1212908d778SJames Bottomley [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err, 1222908d778SJames Bottomley [PORTE_TIMER_EVENT] = sas_porte_timer_event, 1232908d778SJames Bottomley [PORTE_HARD_RESET] = sas_porte_hard_reset, 1242908d778SJames Bottomley }; 1252908d778SJames Bottomley 1262908d778SJames Bottomley /* Now register the phys. */ 1272908d778SJames Bottomley for (i = 0; i < sas_ha->num_phys; i++) { 1282908d778SJames Bottomley int k; 1292908d778SJames Bottomley struct asd_sas_phy *phy = sas_ha->sas_phy[i]; 1302908d778SJames Bottomley 1312908d778SJames Bottomley phy->error = 0; 1322908d778SJames Bottomley INIT_LIST_HEAD(&phy->port_phy_el); 133c4028958SDavid Howells for (k = 0; k < PORT_NUM_EVENTS; k++) { 134c4028958SDavid Howells INIT_WORK(&phy->port_events[k].work, 135c4028958SDavid Howells sas_port_event_fns[k]); 136c4028958SDavid Howells phy->port_events[k].phy = phy; 137c4028958SDavid Howells } 1382908d778SJames Bottomley 139c4028958SDavid Howells for (k = 0; k < PHY_NUM_EVENTS; k++) { 140c4028958SDavid Howells INIT_WORK(&phy->phy_events[k].work, 141c4028958SDavid Howells sas_phy_event_fns[k]); 142c4028958SDavid Howells phy->phy_events[k].phy = phy; 143c4028958SDavid Howells } 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 1512908d778SJames Bottomley phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev, 1522908d778SJames Bottomley i); 1532908d778SJames Bottomley if (!phy->phy) 1542908d778SJames Bottomley return -ENOMEM; 1552908d778SJames Bottomley 1562908d778SJames Bottomley phy->phy->identify.initiator_port_protocols = 1572908d778SJames Bottomley phy->iproto; 1582908d778SJames Bottomley phy->phy->identify.target_port_protocols = phy->tproto; 1592908d778SJames Bottomley phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr); 1602908d778SJames Bottomley phy->phy->identify.phy_identifier = i; 161a01e70e5SJames Bottomley phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 162a01e70e5SJames Bottomley phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 163a01e70e5SJames Bottomley phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; 164a01e70e5SJames Bottomley phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; 1652908d778SJames Bottomley phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; 1662908d778SJames Bottomley 1672908d778SJames Bottomley sas_phy_add(phy->phy); 1682908d778SJames Bottomley } 1692908d778SJames Bottomley 1702908d778SJames Bottomley return 0; 1712908d778SJames Bottomley } 172