1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <wchar.h> 29 #include <strings.h> 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <fcntl.h> 33 #include <unistd.h> 34 #include <libintl.h> 35 #include <errno.h> 36 #include <string.h> 37 #include <assert.h> 38 #include <syslog.h> 39 #include <libfcoe.h> 40 #include <libdllink.h> 41 #include <fcoeio.h> 42 43 #define FCOE_DEV_PATH "/devices/fcoe:admin" 44 45 #define OPEN_FCOE 0 46 #define OPEN_EXCL_FCOE O_EXCL 47 48 /* 49 * Open for fcoe module 50 * 51 * flag - open flag (OPEN_FCOE, OPEN_EXCL_FCOE) 52 * fd - pointer to integer. On success, contains the fcoe file descriptor 53 */ 54 static int 55 openFcoe(int flag, int *fd) 56 { 57 int ret = FCOE_STATUS_ERROR; 58 59 if ((*fd = open(FCOE_DEV_PATH, O_NDELAY | O_RDONLY | flag)) != -1) { 60 ret = FCOE_STATUS_OK; 61 } else { 62 if (errno == EPERM || errno == EACCES) { 63 ret = FCOE_STATUS_ERROR_PERM; 64 } else { 65 ret = FCOE_STATUS_ERROR_OPEN_DEV; 66 } 67 syslog(LOG_DEBUG, "openFcoe:open failure:%s:errno(%d)", 68 FCOE_DEV_PATH, errno); 69 } 70 71 return (ret); 72 } 73 74 static int 75 isWWNZero(FCOE_PORT_WWN portwwn) 76 { 77 int i; 78 int size = sizeof (FCOE_PORT_WWN); 79 80 for (i = 0; i < size; i++) { 81 if (portwwn.wwn[i] != 0) { 82 return (0); 83 } 84 } 85 return (1); 86 } 87 88 FCOE_STATUS 89 FCOE_CreatePort( 90 const FCOE_UINT8 *macLinkName, 91 FCOE_UINT8 portType, 92 FCOE_PORT_WWN pwwn, 93 FCOE_PORT_WWN nwwn, 94 FCOE_UINT8 promiscuous) 95 { 96 FCOE_STATUS status = FCOE_STATUS_OK; 97 int fcoe_fd; 98 fcoeio_t fcoeio; 99 fcoeio_create_port_param_t param; 100 dladm_handle_t handle; 101 datalink_id_t linkid; 102 datalink_class_t class; 103 104 bzero(¶m, sizeof (fcoeio_create_port_param_t)); 105 106 if (macLinkName == NULL) { 107 return (FCOE_STATUS_ERROR_INVAL_ARG); 108 } 109 110 if (strlen((char *)macLinkName) > MAXLINKNAMELEN-1) { 111 return (FCOE_STATUS_ERROR_MAC_LEN); 112 } 113 114 if (dladm_open(&handle) != DLADM_STATUS_OK) { 115 return (FCOE_STATUS_ERROR); 116 } 117 118 if (dladm_name2info(handle, (const char *)macLinkName, 119 &linkid, NULL, &class, NULL) != DLADM_STATUS_OK) { 120 dladm_close(handle); 121 return (FCOE_STATUS_ERROR_GET_LINKINFO); 122 } 123 dladm_close(handle); 124 125 if (class != DATALINK_CLASS_PHYS) { 126 return (FCOE_STATUS_ERROR_CLASS_UNSUPPORT); 127 } 128 129 if (portType != FCOE_PORTTYPE_INITIATOR && 130 portType != FCOE_PORTTYPE_TARGET) { 131 return (FCOE_STATUS_ERROR_INVAL_ARG); 132 } 133 134 if (!isWWNZero(pwwn)) { 135 param.fcp_pwwn_provided = 1; 136 bcopy(pwwn.wwn, param.fcp_pwwn, 8); 137 } 138 139 if (!isWWNZero(nwwn)) { 140 param.fcp_nwwn_provided = 1; 141 bcopy(nwwn.wwn, param.fcp_nwwn, 8); 142 } 143 144 if (param.fcp_pwwn_provided == 1 && 145 param.fcp_nwwn_provided == 1 && 146 bcmp(&pwwn, &nwwn, 8) == 0) { 147 return (FCOE_STATUS_ERROR_WWN_SAME); 148 } 149 150 param.fcp_force_promisc = promiscuous; 151 param.fcp_mac_linkid = linkid; 152 param.fcp_port_type = (fcoe_cli_type_t)portType; 153 154 if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) { 155 return (status); 156 } 157 158 (void) memset(&fcoeio, 0, sizeof (fcoeio)); 159 fcoeio.fcoeio_cmd = FCOEIO_CREATE_FCOE_PORT; 160 161 fcoeio.fcoeio_ilen = sizeof (param); 162 fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE; 163 fcoeio.fcoeio_ibuf = (uintptr_t)¶m; 164 165 if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) { 166 switch (fcoeio.fcoeio_status) { 167 case FCOEIOE_INVAL_ARG: 168 status = FCOE_STATUS_ERROR_INVAL_ARG; 169 break; 170 171 case FCOEIOE_BUSY: 172 status = FCOE_STATUS_ERROR_BUSY; 173 break; 174 175 case FCOEIOE_ALREADY: 176 status = FCOE_STATUS_ERROR_ALREADY; 177 break; 178 179 case FCOEIOE_PWWN_CONFLICTED: 180 status = FCOE_STATUS_ERROR_PWWN_CONFLICTED; 181 break; 182 183 case FCOEIOE_NWWN_CONFLICTED: 184 status = FCOE_STATUS_ERROR_NWWN_CONFLICTED; 185 break; 186 187 case FCOEIOE_CREATE_MAC: 188 status = FCOE_STATUS_ERROR_CREATE_MAC; 189 break; 190 191 case FCOEIOE_OPEN_MAC: 192 status = FCOE_STATUS_ERROR_OPEN_MAC; 193 break; 194 195 case FCOEIOE_CREATE_PORT: 196 status = FCOE_STATUS_ERROR_CREATE_PORT; 197 break; 198 199 case FCOEIOE_NEED_JUMBO_FRAME: 200 status = FCOE_STATUS_ERROR_NEED_JUMBO_FRAME; 201 break; 202 203 default: 204 status = FCOE_STATUS_ERROR; 205 } 206 } else { 207 status = FCOE_STATUS_OK; 208 } 209 (void) close(fcoe_fd); 210 return (status); 211 } 212 213 FCOE_STATUS 214 FCOE_DeletePort(const FCOE_UINT8 *macLinkName) 215 { 216 FCOE_STATUS status = FCOE_STATUS_OK; 217 int fcoe_fd; 218 fcoeio_t fcoeio; 219 dladm_handle_t handle; 220 datalink_id_t linkid; 221 fcoeio_delete_port_param_t fc_del_port; 222 223 if (macLinkName == NULL) { 224 return (FCOE_STATUS_ERROR_INVAL_ARG); 225 } 226 227 if (strlen((char *)macLinkName) > MAXLINKNAMELEN-1) { 228 return (FCOE_STATUS_ERROR_MAC_LEN); 229 } 230 if (dladm_open(&handle) != DLADM_STATUS_OK) { 231 return (FCOE_STATUS_ERROR); 232 } 233 234 if (dladm_name2info(handle, (const char *)macLinkName, 235 &linkid, NULL, NULL, NULL) != DLADM_STATUS_OK) { 236 dladm_close(handle); 237 return (FCOE_STATUS_ERROR_GET_LINKINFO); 238 } 239 dladm_close(handle); 240 241 if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) { 242 return (status); 243 } 244 245 fc_del_port.fdp_mac_linkid = linkid; 246 247 (void) memset(&fcoeio, 0, sizeof (fcoeio)); 248 fcoeio.fcoeio_cmd = FCOEIO_DELETE_FCOE_PORT; 249 250 /* only 4 bytes here, need to change */ 251 fcoeio.fcoeio_ilen = sizeof (fcoeio_delete_port_param_t); 252 fcoeio.fcoeio_xfer = FCOEIO_XFER_WRITE; 253 fcoeio.fcoeio_ibuf = (uintptr_t)&fc_del_port; 254 255 if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) { 256 switch (fcoeio.fcoeio_status) { 257 case FCOEIOE_INVAL_ARG: 258 status = FCOE_STATUS_ERROR_INVAL_ARG; 259 break; 260 261 case FCOEIOE_BUSY: 262 status = FCOE_STATUS_ERROR_BUSY; 263 break; 264 265 case FCOEIOE_ALREADY: 266 status = FCOE_STATUS_ERROR_ALREADY; 267 break; 268 269 case FCOEIOE_MAC_NOT_FOUND: 270 status = FCOE_STATUS_ERROR_MAC_NOT_FOUND; 271 break; 272 273 case FCOEIOE_OFFLINE_FAILURE: 274 status = FCOE_STATUS_ERROR_OFFLINE_DEV; 275 break; 276 277 default: 278 status = FCOE_STATUS_ERROR; 279 } 280 } else { 281 status = FCOE_STATUS_OK; 282 } 283 (void) close(fcoe_fd); 284 return (status); 285 } 286 287 FCOE_STATUS 288 FCOE_GetPortList( 289 FCOE_UINT32 *port_num, 290 FCOE_PORT_ATTRIBUTE **portlist) 291 { 292 FCOE_STATUS status = FCOE_STATUS_OK; 293 int fcoe_fd; 294 fcoeio_t fcoeio; 295 fcoe_port_list_t *inportlist = NULL; 296 FCOE_PORT_ATTRIBUTE *outportlist = NULL; 297 int i; 298 int size = 64; /* default first attempt */ 299 int retry = 0; 300 int bufsize; 301 dladm_handle_t handle; 302 char mac_name[MAXLINKNAMELEN]; 303 304 if (port_num == NULL || portlist == NULL) { 305 return (FCOE_STATUS_ERROR_INVAL_ARG); 306 } 307 *port_num = 0; 308 309 if ((status = openFcoe(OPEN_FCOE, &fcoe_fd)) != FCOE_STATUS_OK) { 310 return (status); 311 } 312 313 /* Get fcoe port list */ 314 (void) memset(&fcoeio, 0, sizeof (fcoeio)); 315 retry = 0; 316 317 do { 318 bufsize = sizeof (fcoe_port_instance_t) * (size - 1) + 319 sizeof (fcoe_port_list_t); 320 inportlist = (fcoe_port_list_t *)malloc(bufsize); 321 fcoeio.fcoeio_cmd = FCOEIO_GET_FCOE_PORT_LIST; 322 fcoeio.fcoeio_olen = bufsize; 323 fcoeio.fcoeio_xfer = FCOEIO_XFER_READ; 324 fcoeio.fcoeio_obuf = (uintptr_t)inportlist; 325 326 if (ioctl(fcoe_fd, FCOEIO_CMD, &fcoeio) != 0) { 327 if (fcoeio.fcoeio_status == FCOEIOE_MORE_DATA) { 328 size = inportlist->numPorts; 329 } 330 free(inportlist); 331 switch (fcoeio.fcoeio_status) { 332 case FCOEIOE_INVAL_ARG: 333 status = FCOE_STATUS_ERROR_INVAL_ARG; 334 (void) close(fcoe_fd); 335 return (status); 336 337 case FCOEIOE_BUSY: 338 status = FCOE_STATUS_ERROR_BUSY; 339 retry++; 340 break; 341 342 case FCOEIOE_MORE_DATA: 343 status = FCOE_STATUS_ERROR_MORE_DATA; 344 retry++; 345 default: 346 status = FCOE_STATUS_ERROR; 347 } 348 } else { 349 status = FCOE_STATUS_OK; 350 break; 351 } 352 } while (retry <= 3 && status != FCOE_STATUS_OK); 353 354 if (status == FCOE_STATUS_OK && inportlist->numPorts > 0) { 355 if (dladm_open(&handle) != DLADM_STATUS_OK) { 356 handle = NULL; 357 } 358 359 outportlist = (PFCOE_PORT_ATTRIBUTE) 360 malloc(sizeof (FCOE_PORT_ATTRIBUTE) * inportlist->numPorts); 361 362 for (i = 0; i < inportlist->numPorts; i++) { 363 fcoe_port_instance_t *pi = &inportlist->ports[i]; 364 FCOE_PORT_ATTRIBUTE *po = &outportlist[i]; 365 bcopy(pi->fpi_pwwn, &po->port_wwn, 8); 366 367 if (handle == NULL || 368 dladm_datalink_id2info(handle, pi->fpi_mac_linkid, 369 NULL, NULL, NULL, mac_name, sizeof (mac_name)) 370 != DLADM_STATUS_OK) { 371 (void) strcpy((char *)po->mac_link_name, 372 "<unknown>"); 373 } else { 374 (void) strcpy((char *)po->mac_link_name, 375 mac_name); 376 } 377 bcopy(pi->fpi_mac_factory_addr, 378 po->mac_factory_addr, 6); 379 bcopy(pi->fpi_mac_current_addr, 380 po->mac_current_addr, 6); 381 po->port_type = (FCOE_UINT8)pi->fpi_port_type; 382 po->mtu_size = pi->fpi_mtu_size; 383 po->mac_promisc = pi->fpi_mac_promisc; 384 } 385 386 if (handle != NULL) { 387 dladm_close(handle); 388 } 389 *port_num = inportlist->numPorts; 390 *portlist = outportlist; 391 free(inportlist); 392 } else { 393 *port_num = 0; 394 *portlist = NULL; 395 } 396 (void) close(fcoe_fd); 397 return (status); 398 } 399