1 /* 2 * Serial Attached SCSI (SAS) Event processing 3 * 4 * Copyright (C) 2005 Adaptec, Inc. All rights reserved. 5 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> 6 * 7 * This file is licensed under GPLv2. 8 * 9 * This program is free software; you can redistribute it and/or 10 * modify it under the terms of the GNU General Public License as 11 * published by the Free Software Foundation; either version 2 of the 12 * License, or (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, but 15 * WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 * General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * 23 */ 24 25 #include <linux/export.h> 26 #include <scsi/scsi_host.h> 27 #include "sas_internal.h" 28 #include "sas_dump.h" 29 30 int sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) 31 { 32 int rc = 0; 33 34 if (!test_bit(SAS_HA_REGISTERED, &ha->state)) 35 return 0; 36 37 if (test_bit(SAS_HA_DRAINING, &ha->state)) { 38 /* add it to the defer list, if not already pending */ 39 if (list_empty(&sw->drain_node)) 40 list_add_tail(&sw->drain_node, &ha->defer_q); 41 } else 42 rc = scsi_queue_work(ha->core.shost, &sw->work); 43 44 return rc; 45 } 46 47 static int sas_queue_event(int event, unsigned long *pending, 48 struct sas_work *work, 49 struct sas_ha_struct *ha) 50 { 51 int rc = 0; 52 53 if (!test_and_set_bit(event, pending)) { 54 unsigned long flags; 55 56 spin_lock_irqsave(&ha->lock, flags); 57 rc = sas_queue_work(ha, work); 58 spin_unlock_irqrestore(&ha->lock, flags); 59 } 60 61 return rc; 62 } 63 64 65 void __sas_drain_work(struct sas_ha_struct *ha) 66 { 67 struct workqueue_struct *wq = ha->core.shost->work_q; 68 struct sas_work *sw, *_sw; 69 70 set_bit(SAS_HA_DRAINING, &ha->state); 71 /* flush submitters */ 72 spin_lock_irq(&ha->lock); 73 spin_unlock_irq(&ha->lock); 74 75 drain_workqueue(wq); 76 77 spin_lock_irq(&ha->lock); 78 clear_bit(SAS_HA_DRAINING, &ha->state); 79 list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { 80 list_del_init(&sw->drain_node); 81 sas_queue_work(ha, sw); 82 } 83 spin_unlock_irq(&ha->lock); 84 } 85 86 int sas_drain_work(struct sas_ha_struct *ha) 87 { 88 int err; 89 90 err = mutex_lock_interruptible(&ha->drain_mutex); 91 if (err) 92 return err; 93 if (test_bit(SAS_HA_REGISTERED, &ha->state)) 94 __sas_drain_work(ha); 95 mutex_unlock(&ha->drain_mutex); 96 97 return 0; 98 } 99 EXPORT_SYMBOL_GPL(sas_drain_work); 100 101 void sas_disable_revalidation(struct sas_ha_struct *ha) 102 { 103 mutex_lock(&ha->disco_mutex); 104 set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state); 105 mutex_unlock(&ha->disco_mutex); 106 } 107 108 void sas_enable_revalidation(struct sas_ha_struct *ha) 109 { 110 int i; 111 112 mutex_lock(&ha->disco_mutex); 113 clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state); 114 for (i = 0; i < ha->num_phys; i++) { 115 struct asd_sas_port *port = ha->sas_port[i]; 116 const int ev = DISCE_REVALIDATE_DOMAIN; 117 struct sas_discovery *d = &port->disc; 118 119 if (!test_and_clear_bit(ev, &d->pending)) 120 continue; 121 122 sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha); 123 } 124 mutex_unlock(&ha->disco_mutex); 125 } 126 127 static int sas_notify_port_event(struct asd_sas_phy *phy, enum port_event event) 128 { 129 struct sas_ha_struct *ha = phy->ha; 130 131 BUG_ON(event >= PORT_NUM_EVENTS); 132 133 return sas_queue_event(event, &phy->port_events_pending, 134 &phy->port_events[event].work, ha); 135 } 136 137 int sas_notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) 138 { 139 struct sas_ha_struct *ha = phy->ha; 140 141 BUG_ON(event >= PHY_NUM_EVENTS); 142 143 return sas_queue_event(event, &phy->phy_events_pending, 144 &phy->phy_events[event].work, ha); 145 } 146 147 int sas_init_events(struct sas_ha_struct *sas_ha) 148 { 149 sas_ha->notify_port_event = sas_notify_port_event; 150 sas_ha->notify_phy_event = sas_notify_phy_event; 151 152 return 0; 153 } 154