1 /* 2 * Copyright Gavin Shan, IBM Corporation 2016. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 */ 9 10 #include <linux/module.h> 11 #include <linux/kernel.h> 12 #include <linux/init.h> 13 #include <linux/netdevice.h> 14 #include <linux/skbuff.h> 15 16 #include <net/ncsi.h> 17 #include <net/net_namespace.h> 18 #include <net/sock.h> 19 20 #include "internal.h" 21 #include "ncsi-pkt.h" 22 23 static int ncsi_validate_aen_pkt(struct ncsi_aen_pkt_hdr *h, 24 const unsigned short payload) 25 { 26 u32 checksum; 27 __be32 *pchecksum; 28 29 if (h->common.revision != NCSI_PKT_REVISION) 30 return -EINVAL; 31 if (ntohs(h->common.length) != payload) 32 return -EINVAL; 33 34 /* Validate checksum, which might be zeroes if the 35 * sender doesn't support checksum according to NCSI 36 * specification. 37 */ 38 pchecksum = (__be32 *)((void *)(h + 1) + payload - 4); 39 if (ntohl(*pchecksum) == 0) 40 return 0; 41 42 checksum = ncsi_calculate_checksum((unsigned char *)h, 43 sizeof(*h) + payload - 4); 44 if (*pchecksum != htonl(checksum)) 45 return -EINVAL; 46 47 return 0; 48 } 49 50 static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp, 51 struct ncsi_aen_pkt_hdr *h) 52 { 53 struct ncsi_channel *nc, *tmp; 54 struct ncsi_channel_mode *ncm; 55 unsigned long old_data, data; 56 struct ncsi_aen_lsc_pkt *lsc; 57 struct ncsi_package *np; 58 bool had_link, has_link; 59 unsigned long flags; 60 bool chained; 61 int state; 62 63 /* Find the NCSI channel */ 64 ncsi_find_package_and_channel(ndp, h->common.channel, NULL, &nc); 65 if (!nc) 66 return -ENODEV; 67 68 /* Update the link status */ 69 lsc = (struct ncsi_aen_lsc_pkt *)h; 70 71 spin_lock_irqsave(&nc->lock, flags); 72 ncm = &nc->modes[NCSI_MODE_LINK]; 73 old_data = ncm->data[2]; 74 data = ntohl(lsc->status); 75 ncm->data[2] = data; 76 ncm->data[4] = ntohl(lsc->oem_status); 77 78 had_link = !!(old_data & 0x1); 79 has_link = !!(data & 0x1); 80 81 netdev_dbg(ndp->ndev.dev, "NCSI: LSC AEN - channel %u state %s\n", 82 nc->id, data & 0x1 ? "up" : "down"); 83 84 chained = !list_empty(&nc->link); 85 state = nc->state; 86 spin_unlock_irqrestore(&nc->lock, flags); 87 88 if (state == NCSI_CHANNEL_INACTIVE) 89 netdev_warn(ndp->ndev.dev, 90 "NCSI: Inactive channel %u received AEN!\n", 91 nc->id); 92 93 if ((had_link == has_link) || chained) 94 return 0; 95 96 if (!ndp->multi_package && !nc->package->multi_channel) { 97 if (had_link) { 98 ndp->flags |= NCSI_DEV_RESHUFFLE; 99 ncsi_stop_channel_monitor(nc); 100 spin_lock_irqsave(&ndp->lock, flags); 101 list_add_tail_rcu(&nc->link, &ndp->channel_queue); 102 spin_unlock_irqrestore(&ndp->lock, flags); 103 return ncsi_process_next_channel(ndp); 104 } 105 /* Configured channel came up */ 106 return 0; 107 } 108 109 if (had_link) { 110 ncm = &nc->modes[NCSI_MODE_TX_ENABLE]; 111 if (ncsi_channel_is_last(ndp, nc)) { 112 /* No channels left, reconfigure */ 113 return ncsi_reset_dev(&ndp->ndev); 114 } else if (ncm->enable) { 115 /* Need to failover Tx channel */ 116 ncsi_update_tx_channel(ndp, nc->package, nc, NULL); 117 } 118 } else if (has_link && nc->package->preferred_channel == nc) { 119 /* Return Tx to preferred channel */ 120 ncsi_update_tx_channel(ndp, nc->package, NULL, nc); 121 } else if (has_link) { 122 NCSI_FOR_EACH_PACKAGE(ndp, np) { 123 NCSI_FOR_EACH_CHANNEL(np, tmp) { 124 /* Enable Tx on this channel if the current Tx 125 * channel is down. 126 */ 127 ncm = &tmp->modes[NCSI_MODE_TX_ENABLE]; 128 if (ncm->enable && 129 !ncsi_channel_has_link(tmp)) { 130 ncsi_update_tx_channel(ndp, nc->package, 131 tmp, nc); 132 break; 133 } 134 } 135 } 136 } 137 138 /* Leave configured channels active in a multi-channel scenario so 139 * AEN events are still received. 140 */ 141 return 0; 142 } 143 144 static int ncsi_aen_handler_cr(struct ncsi_dev_priv *ndp, 145 struct ncsi_aen_pkt_hdr *h) 146 { 147 struct ncsi_channel *nc; 148 unsigned long flags; 149 150 /* Find the NCSI channel */ 151 ncsi_find_package_and_channel(ndp, h->common.channel, NULL, &nc); 152 if (!nc) 153 return -ENODEV; 154 155 spin_lock_irqsave(&nc->lock, flags); 156 if (!list_empty(&nc->link) || 157 nc->state != NCSI_CHANNEL_ACTIVE) { 158 spin_unlock_irqrestore(&nc->lock, flags); 159 return 0; 160 } 161 spin_unlock_irqrestore(&nc->lock, flags); 162 163 ncsi_stop_channel_monitor(nc); 164 spin_lock_irqsave(&nc->lock, flags); 165 nc->state = NCSI_CHANNEL_INVISIBLE; 166 spin_unlock_irqrestore(&nc->lock, flags); 167 168 spin_lock_irqsave(&ndp->lock, flags); 169 nc->state = NCSI_CHANNEL_INACTIVE; 170 list_add_tail_rcu(&nc->link, &ndp->channel_queue); 171 spin_unlock_irqrestore(&ndp->lock, flags); 172 173 return ncsi_process_next_channel(ndp); 174 } 175 176 static int ncsi_aen_handler_hncdsc(struct ncsi_dev_priv *ndp, 177 struct ncsi_aen_pkt_hdr *h) 178 { 179 struct ncsi_channel *nc; 180 struct ncsi_channel_mode *ncm; 181 struct ncsi_aen_hncdsc_pkt *hncdsc; 182 unsigned long flags; 183 184 /* Find the NCSI channel */ 185 ncsi_find_package_and_channel(ndp, h->common.channel, NULL, &nc); 186 if (!nc) 187 return -ENODEV; 188 189 spin_lock_irqsave(&nc->lock, flags); 190 ncm = &nc->modes[NCSI_MODE_LINK]; 191 hncdsc = (struct ncsi_aen_hncdsc_pkt *)h; 192 ncm->data[3] = ntohl(hncdsc->status); 193 spin_unlock_irqrestore(&nc->lock, flags); 194 netdev_dbg(ndp->ndev.dev, 195 "NCSI: host driver %srunning on channel %u\n", 196 ncm->data[3] & 0x1 ? "" : "not ", nc->id); 197 198 return 0; 199 } 200 201 static struct ncsi_aen_handler { 202 unsigned char type; 203 int payload; 204 int (*handler)(struct ncsi_dev_priv *ndp, 205 struct ncsi_aen_pkt_hdr *h); 206 } ncsi_aen_handlers[] = { 207 { NCSI_PKT_AEN_LSC, 12, ncsi_aen_handler_lsc }, 208 { NCSI_PKT_AEN_CR, 4, ncsi_aen_handler_cr }, 209 { NCSI_PKT_AEN_HNCDSC, 8, ncsi_aen_handler_hncdsc } 210 }; 211 212 int ncsi_aen_handler(struct ncsi_dev_priv *ndp, struct sk_buff *skb) 213 { 214 struct ncsi_aen_pkt_hdr *h; 215 struct ncsi_aen_handler *nah = NULL; 216 int i, ret; 217 218 /* Find the handler */ 219 h = (struct ncsi_aen_pkt_hdr *)skb_network_header(skb); 220 for (i = 0; i < ARRAY_SIZE(ncsi_aen_handlers); i++) { 221 if (ncsi_aen_handlers[i].type == h->type) { 222 nah = &ncsi_aen_handlers[i]; 223 break; 224 } 225 } 226 227 if (!nah) { 228 netdev_warn(ndp->ndev.dev, "Invalid AEN (0x%x) received\n", 229 h->type); 230 return -ENOENT; 231 } 232 233 ret = ncsi_validate_aen_pkt(h, nah->payload); 234 if (ret) { 235 netdev_warn(ndp->ndev.dev, 236 "NCSI: 'bad' packet ignored for AEN type 0x%x\n", 237 h->type); 238 goto out; 239 } 240 241 ret = nah->handler(ndp, h); 242 if (ret) 243 netdev_err(ndp->ndev.dev, 244 "NCSI: Handler for AEN type 0x%x returned %d\n", 245 h->type, ret); 246 out: 247 consume_skb(skb); 248 return ret; 249 } 250