1 /* 2 * driver for Microsemi PQI-based storage controllers 3 * Copyright (c) 2016-2017 Microsemi Corporation 4 * Copyright (c) 2016 PMC-Sierra, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 13 * NON INFRINGEMENT. See the GNU General Public License for more details. 14 * 15 * Questions/Comments/Bugfixes to esc.storagedev@microsemi.com 16 * 17 */ 18 19 #include <linux/kernel.h> 20 #include <scsi/scsi_host.h> 21 #include <scsi/scsi_cmnd.h> 22 #include <scsi/scsi_transport_sas.h> 23 #include "smartpqi.h" 24 25 static struct pqi_sas_phy *pqi_alloc_sas_phy(struct pqi_sas_port *pqi_sas_port) 26 { 27 struct pqi_sas_phy *pqi_sas_phy; 28 struct sas_phy *phy; 29 30 pqi_sas_phy = kzalloc(sizeof(*pqi_sas_phy), GFP_KERNEL); 31 if (!pqi_sas_phy) 32 return NULL; 33 34 phy = sas_phy_alloc(pqi_sas_port->parent_node->parent_dev, 35 pqi_sas_port->next_phy_index); 36 if (!phy) { 37 kfree(pqi_sas_phy); 38 return NULL; 39 } 40 41 pqi_sas_port->next_phy_index++; 42 pqi_sas_phy->phy = phy; 43 pqi_sas_phy->parent_port = pqi_sas_port; 44 45 return pqi_sas_phy; 46 } 47 48 static void pqi_free_sas_phy(struct pqi_sas_phy *pqi_sas_phy) 49 { 50 struct sas_phy *phy = pqi_sas_phy->phy; 51 52 sas_port_delete_phy(pqi_sas_phy->parent_port->port, phy); 53 sas_phy_free(phy); 54 if (pqi_sas_phy->added_to_port) 55 list_del(&pqi_sas_phy->phy_list_entry); 56 kfree(pqi_sas_phy); 57 } 58 59 static int pqi_sas_port_add_phy(struct pqi_sas_phy *pqi_sas_phy) 60 { 61 int rc; 62 struct pqi_sas_port *pqi_sas_port; 63 struct sas_phy *phy; 64 struct sas_identify *identify; 65 66 pqi_sas_port = pqi_sas_phy->parent_port; 67 phy = pqi_sas_phy->phy; 68 69 identify = &phy->identify; 70 memset(identify, 0, sizeof(*identify)); 71 identify->sas_address = pqi_sas_port->sas_address; 72 identify->device_type = SAS_END_DEVICE; 73 identify->initiator_port_protocols = SAS_PROTOCOL_STP; 74 identify->target_port_protocols = SAS_PROTOCOL_STP; 75 phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 76 phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; 77 phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; 78 phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; 79 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; 80 81 rc = sas_phy_add(pqi_sas_phy->phy); 82 if (rc) 83 return rc; 84 85 sas_port_add_phy(pqi_sas_port->port, pqi_sas_phy->phy); 86 list_add_tail(&pqi_sas_phy->phy_list_entry, 87 &pqi_sas_port->phy_list_head); 88 pqi_sas_phy->added_to_port = true; 89 90 return 0; 91 } 92 93 static int pqi_sas_port_add_rphy(struct pqi_sas_port *pqi_sas_port, 94 struct sas_rphy *rphy) 95 { 96 struct sas_identify *identify; 97 98 identify = &rphy->identify; 99 identify->sas_address = pqi_sas_port->sas_address; 100 identify->initiator_port_protocols = SAS_PROTOCOL_STP; 101 identify->target_port_protocols = SAS_PROTOCOL_STP; 102 103 return sas_rphy_add(rphy); 104 } 105 106 static struct pqi_sas_port *pqi_alloc_sas_port( 107 struct pqi_sas_node *pqi_sas_node, u64 sas_address) 108 { 109 int rc; 110 struct pqi_sas_port *pqi_sas_port; 111 struct sas_port *port; 112 113 pqi_sas_port = kzalloc(sizeof(*pqi_sas_port), GFP_KERNEL); 114 if (!pqi_sas_port) 115 return NULL; 116 117 INIT_LIST_HEAD(&pqi_sas_port->phy_list_head); 118 pqi_sas_port->parent_node = pqi_sas_node; 119 120 port = sas_port_alloc_num(pqi_sas_node->parent_dev); 121 if (!port) 122 goto free_pqi_port; 123 124 rc = sas_port_add(port); 125 if (rc) 126 goto free_sas_port; 127 128 pqi_sas_port->port = port; 129 pqi_sas_port->sas_address = sas_address; 130 list_add_tail(&pqi_sas_port->port_list_entry, 131 &pqi_sas_node->port_list_head); 132 133 return pqi_sas_port; 134 135 free_sas_port: 136 sas_port_free(port); 137 free_pqi_port: 138 kfree(pqi_sas_port); 139 140 return NULL; 141 } 142 143 static void pqi_free_sas_port(struct pqi_sas_port *pqi_sas_port) 144 { 145 struct pqi_sas_phy *pqi_sas_phy; 146 struct pqi_sas_phy *next; 147 148 list_for_each_entry_safe(pqi_sas_phy, next, 149 &pqi_sas_port->phy_list_head, phy_list_entry) 150 pqi_free_sas_phy(pqi_sas_phy); 151 152 sas_port_delete(pqi_sas_port->port); 153 list_del(&pqi_sas_port->port_list_entry); 154 kfree(pqi_sas_port); 155 } 156 157 static struct pqi_sas_node *pqi_alloc_sas_node(struct device *parent_dev) 158 { 159 struct pqi_sas_node *pqi_sas_node; 160 161 pqi_sas_node = kzalloc(sizeof(*pqi_sas_node), GFP_KERNEL); 162 if (pqi_sas_node) { 163 pqi_sas_node->parent_dev = parent_dev; 164 INIT_LIST_HEAD(&pqi_sas_node->port_list_head); 165 } 166 167 return pqi_sas_node; 168 } 169 170 static void pqi_free_sas_node(struct pqi_sas_node *pqi_sas_node) 171 { 172 struct pqi_sas_port *pqi_sas_port; 173 struct pqi_sas_port *next; 174 175 if (!pqi_sas_node) 176 return; 177 178 list_for_each_entry_safe(pqi_sas_port, next, 179 &pqi_sas_node->port_list_head, port_list_entry) 180 pqi_free_sas_port(pqi_sas_port); 181 182 kfree(pqi_sas_node); 183 } 184 185 struct pqi_scsi_dev *pqi_find_device_by_sas_rphy( 186 struct pqi_ctrl_info *ctrl_info, struct sas_rphy *rphy) 187 { 188 struct pqi_scsi_dev *device; 189 190 list_for_each_entry(device, &ctrl_info->scsi_device_list, 191 scsi_device_list_entry) { 192 if (!device->sas_port) 193 continue; 194 if (device->sas_port->rphy == rphy) 195 return device; 196 } 197 198 return NULL; 199 } 200 201 int pqi_add_sas_host(struct Scsi_Host *shost, struct pqi_ctrl_info *ctrl_info) 202 { 203 int rc; 204 struct device *parent_dev; 205 struct pqi_sas_node *pqi_sas_node; 206 struct pqi_sas_port *pqi_sas_port; 207 struct pqi_sas_phy *pqi_sas_phy; 208 209 parent_dev = &shost->shost_gendev; 210 211 pqi_sas_node = pqi_alloc_sas_node(parent_dev); 212 if (!pqi_sas_node) 213 return -ENOMEM; 214 215 pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, ctrl_info->sas_address); 216 if (!pqi_sas_port) { 217 rc = -ENODEV; 218 goto free_sas_node; 219 } 220 221 pqi_sas_phy = pqi_alloc_sas_phy(pqi_sas_port); 222 if (!pqi_sas_phy) { 223 rc = -ENODEV; 224 goto free_sas_port; 225 } 226 227 rc = pqi_sas_port_add_phy(pqi_sas_phy); 228 if (rc) 229 goto free_sas_phy; 230 231 ctrl_info->sas_host = pqi_sas_node; 232 233 return 0; 234 235 free_sas_phy: 236 pqi_free_sas_phy(pqi_sas_phy); 237 free_sas_port: 238 pqi_free_sas_port(pqi_sas_port); 239 free_sas_node: 240 pqi_free_sas_node(pqi_sas_node); 241 242 return rc; 243 } 244 245 void pqi_delete_sas_host(struct pqi_ctrl_info *ctrl_info) 246 { 247 pqi_free_sas_node(ctrl_info->sas_host); 248 } 249 250 int pqi_add_sas_device(struct pqi_sas_node *pqi_sas_node, 251 struct pqi_scsi_dev *device) 252 { 253 int rc; 254 struct pqi_sas_port *pqi_sas_port; 255 struct sas_rphy *rphy; 256 257 pqi_sas_port = pqi_alloc_sas_port(pqi_sas_node, device->sas_address); 258 if (!pqi_sas_port) 259 return -ENOMEM; 260 261 rphy = sas_end_device_alloc(pqi_sas_port->port); 262 if (!rphy) { 263 rc = -ENODEV; 264 goto free_sas_port; 265 } 266 267 pqi_sas_port->rphy = rphy; 268 device->sas_port = pqi_sas_port; 269 270 rc = pqi_sas_port_add_rphy(pqi_sas_port, rphy); 271 if (rc) 272 goto free_sas_port; 273 274 return 0; 275 276 free_sas_port: 277 pqi_free_sas_port(pqi_sas_port); 278 device->sas_port = NULL; 279 280 return rc; 281 } 282 283 void pqi_remove_sas_device(struct pqi_scsi_dev *device) 284 { 285 if (device->sas_port) { 286 pqi_free_sas_port(device->sas_port); 287 device->sas_port = NULL; 288 } 289 } 290 291 static int pqi_sas_get_linkerrors(struct sas_phy *phy) 292 { 293 return 0; 294 } 295 296 static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy, 297 u64 *identifier) 298 { 299 return 0; 300 } 301 302 static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy) 303 { 304 return -ENXIO; 305 } 306 307 static int pqi_sas_phy_reset(struct sas_phy *phy, int hard_reset) 308 { 309 return 0; 310 } 311 312 static int pqi_sas_phy_enable(struct sas_phy *phy, int enable) 313 { 314 return 0; 315 } 316 317 static int pqi_sas_phy_setup(struct sas_phy *phy) 318 { 319 return 0; 320 } 321 322 static void pqi_sas_phy_release(struct sas_phy *phy) 323 { 324 } 325 326 static int pqi_sas_phy_speed(struct sas_phy *phy, 327 struct sas_phy_linkrates *rates) 328 { 329 return -EINVAL; 330 } 331 332 struct sas_function_template pqi_sas_transport_functions = { 333 .get_linkerrors = pqi_sas_get_linkerrors, 334 .get_enclosure_identifier = pqi_sas_get_enclosure_identifier, 335 .get_bay_identifier = pqi_sas_get_bay_identifier, 336 .phy_reset = pqi_sas_phy_reset, 337 .phy_enable = pqi_sas_phy_enable, 338 .phy_setup = pqi_sas_phy_setup, 339 .phy_release = pqi_sas_phy_release, 340 .set_phy_speed = pqi_sas_phy_speed, 341 }; 342