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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright 2019 Joyent, Inc. 28 */ 29 30 #include <sys/byteorder.h> 31 #include <sun_sas.h> 32 33 /* 34 * creates a handle each time Sun_sas_OpenAdapter() is called. 35 * 36 * a open_handle_struct was created to keep track of which handles are currently 37 * open. This prevents a user from using an old handle that corresponds to 38 * an hba that has already been closed. 39 */ 40 HBA_HANDLE 41 CreateHandle(int adapterIndex) 42 { 43 const char ROUTINE[] = "CreateHandle"; 44 struct open_handle *new_open_handle; 45 HBA_UINT32 new_handle_index; 46 HBA_UINT8 max_handle_wrap = 0; 47 48 if (global_hba_head == NULL) { 49 log(LOG_DEBUG, ROUTINE, 50 "an error as occurred. global_hba_head is " 51 "NULL. Library may not be loaded yet."); 52 return (HANDLE_ERROR); 53 } 54 55 while (RetrieveIndex(open_handle_index) != -1) { 56 open_handle_index = open_handle_index + 1; 57 if (open_handle_index == 0) { 58 /* 59 * If open_handle_index wraps back to zero again, 60 * that means all handles are currently in use. 61 * Spec only allows for 16 bits of handles 62 */ 63 if (max_handle_wrap == 1) { 64 log(LOG_DEBUG, ROUTINE, 65 "Max number of handles reached."); 66 return (HANDLE_ERROR); 67 } 68 open_handle_index = 1; 69 max_handle_wrap = 1; 70 } 71 } 72 73 new_handle_index = open_handle_index; 74 if ((new_open_handle = (struct open_handle *)calloc(1, 75 sizeof (struct open_handle))) == NULL) { 76 OUT_OF_MEMORY(ROUTINE); 77 return (HANDLE_ERROR); 78 } 79 (void) memset(new_open_handle, 0, sizeof (struct open_handle)); 80 new_open_handle->adapterIndex = adapterIndex; 81 new_open_handle->handle = new_handle_index; 82 83 lock(&open_handles_lock); 84 85 /* add new open handle struct to the open_handles list */ 86 if (global_hba_head->open_handles == NULL) { 87 global_hba_head->open_handles = new_open_handle; 88 } else { 89 new_open_handle->next = global_hba_head->open_handles; 90 global_hba_head->open_handles = new_open_handle; 91 } 92 93 unlock(&open_handles_lock); 94 open_handle_index = open_handle_index + 1; 95 if (open_handle_index == 0) { 96 open_handle_index = 1; 97 } 98 99 return (new_handle_index); 100 } 101 102 /* 103 * given a handle, returns the adapterIndex number. 104 * 105 * This functions checkes to see if the given handle corresponds to an open 106 * HBA. If it does, the adapterIndex is returned. 107 */ 108 int 109 RetrieveIndex(HBA_HANDLE handle) 110 { 111 112 struct open_handle *open_handle_ptr; 113 114 lock(&open_handles_lock); 115 116 open_handle_ptr = RetrieveOpenHandle(handle); 117 118 unlock(&open_handles_lock); 119 if (open_handle_ptr == NULL) { 120 return (-1); 121 } 122 123 return (open_handle_ptr->adapterIndex); 124 } 125 /* 126 * Given a handle, returns the open_handle structure 127 * The routine assumes that the open_handles_lock has already 128 * been taken. 129 */ 130 struct open_handle * 131 RetrieveOpenHandle(HBA_HANDLE handle) 132 { 133 134 const char ROUTINE[] = "RetrieveOpenHandle"; 135 struct open_handle *open_handle_ptr = NULL; 136 137 if (global_hba_head == NULL) { 138 log(LOG_DEBUG, ROUTINE, "No adapter is found."); 139 return (NULL); 140 } 141 142 for (open_handle_ptr = global_hba_head->open_handles; 143 open_handle_ptr != NULL; 144 open_handle_ptr = open_handle_ptr->next) { 145 if (open_handle_ptr->handle == handle) { 146 break; 147 } 148 } 149 150 return (open_handle_ptr); 151 } 152 153 /* 154 * Given an adapterIndex, this functions returns a pointer to the handle 155 * structure. This handle structure holds the hba's information 156 * Caller must take all_hbas_lock first. 157 */ 158 struct sun_sas_hba * 159 RetrieveHandle(int index) 160 { 161 struct sun_sas_hba *hba_ptr = NULL; 162 163 for (hba_ptr = global_hba_head; hba_ptr != NULL; 164 hba_ptr = hba_ptr->next) { 165 if (hba_ptr->index == index) 166 break; 167 } 168 169 return (hba_ptr); 170 } 171 172 /* 173 * Given an adapterIndex, this functions returns a pointer to the handle 174 * structure and extracts it from the global list. 175 * 176 * all_hbas_lock must be taken already. 177 */ 178 struct sun_sas_hba * 179 ExtractHandle(int index) 180 { 181 struct sun_sas_hba *last = NULL; 182 struct sun_sas_hba *hba_ptr = NULL; 183 184 for (hba_ptr = global_hba_head; 185 hba_ptr != NULL; 186 last = hba_ptr, hba_ptr = hba_ptr->next) { 187 if (hba_ptr->index == index) { 188 if (last) { 189 last->next = hba_ptr->next; 190 } else { 191 /* Hmm, must be the head of the list. */ 192 global_hba_head = hba_ptr->next; 193 } 194 hba_ptr->next = NULL; /* Zap it to be safe */ 195 break; 196 } 197 } 198 199 return (hba_ptr); 200 } 201 202 203 /* 204 * Given an handle, this functions returns a pointer to the handle structure 205 * for that hba 206 * 207 * Caller must take all_hbas_lock first. 208 */ 209 struct sun_sas_hba * 210 Retrieve_Sun_sasHandle(HBA_HANDLE handle) 211 { 212 const char ROUTINE[] = "Retrieve_Sun_sasHandle"; 213 struct sun_sas_hba *handle_struct = NULL; 214 int index; 215 216 /* Retrieve fp device path from handle */ 217 index = RetrieveIndex(handle); 218 if (index == -1) { 219 log(LOG_DEBUG, ROUTINE, 220 "handle could not be found."); 221 return (handle_struct); 222 } 223 lock(&open_handles_lock); 224 handle_struct = RetrieveHandle(index); 225 if (handle_struct == NULL) { 226 log(LOG_DEBUG, ROUTINE, 227 "could not find index in the handle list."); 228 unlock(&open_handles_lock); 229 return (handle_struct); 230 } 231 unlock(&open_handles_lock); 232 233 return (handle_struct); 234 } 235 236 /* 237 * Take a mutex lock. The routine will try, and if it fails, 238 * it will loop for a while and retry. If it fails many times, 239 * it will start writing to the log file. 240 */ 241 void 242 lock(mutex_t *mp) 243 { 244 int status; 245 int loop = 0; 246 const char ROUTINE[] = "lock"; 247 248 do { 249 loop++; 250 status = mutex_trylock(mp); 251 switch (status) { 252 case 0: 253 break; 254 case EFAULT: 255 log(LOG_DEBUG, ROUTINE, 256 "Lock failed: fault 0x%x", mp); 257 break; 258 case EINVAL: 259 log(LOG_DEBUG, ROUTINE, 260 "Lock failed: invalid 0x%x", mp); 261 break; 262 case EBUSY: 263 if (loop > DEADLOCK_WARNING) { 264 log(LOG_DEBUG, ROUTINE, 265 "Lock busy, possible deadlock:0x%x", 266 mp); 267 } 268 break; 269 case EOWNERDEAD: 270 log(LOG_DEBUG, ROUTINE, 271 "Lock failed: owner dead 0x%x", 272 mp); 273 break; 274 case ELOCKUNMAPPED: 275 log(LOG_DEBUG, ROUTINE, 276 "Lock failed: unmapped 0x%x", 277 mp); 278 break; 279 case ENOTRECOVERABLE: 280 log(LOG_DEBUG, ROUTINE, 281 "Lock failed: not recoverable 0x%x", mp); 282 break; 283 default: 284 if (loop > DEADLOCK_WARNING) { 285 log(LOG_DEBUG, ROUTINE, 286 "Lock failed: %s 0x%x", 287 strerror(status), mp); 288 break; 289 } 290 } 291 292 if (status) { 293 (void) sleep(LOCK_SLEEP); 294 } 295 296 } while (status); 297 } 298 299 /* 300 * Unlock a mutex lock. 301 */ 302 void 303 unlock(mutex_t *mp) 304 { 305 (void) mutex_unlock(mp); 306 } 307 308 309 /* 310 * Get the Port WWN of the first adapter port. This routine 311 * is used by the old V1 interfaces so that they can call 312 * the new V2 interfaces and exhibit the same behavior. 313 * In the event of error the WWN will be zero. 314 * 315 * This function will transition to PAA state but it will not 316 * verfiy whether data is stale or not 317 */ 318 HBA_WWN 319 getFirstAdapterPortWWN(HBA_HANDLE handle) 320 { 321 const char ROUTINE[] = "getFirstAdapterPortWWN"; 322 HBA_WWN pwwn = {0, 0, 0, 0, 0, 0, 0, 0}; 323 struct sun_sas_hba *hba_ptr = NULL; 324 int index = 0; 325 HBA_STATUS status; 326 327 lock(&all_hbas_lock); 328 index = RetrieveIndex(handle); 329 lock(&open_handles_lock); 330 hba_ptr = RetrieveHandle(index); 331 if (hba_ptr == NULL) { 332 log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle); 333 unlock(&open_handles_lock); 334 unlock(&all_hbas_lock); 335 return (pwwn); /* zero WWN */ 336 } 337 338 /* Check for stale data */ 339 status = verifyAdapter(hba_ptr); 340 if (status != HBA_STATUS_OK) { 341 log(LOG_DEBUG, ROUTINE, "Verify adapter failed"); 342 unlock(&open_handles_lock); 343 unlock(&all_hbas_lock); 344 return (pwwn); 345 } 346 347 if (hba_ptr->first_port == NULL) { 348 /* This is probably an internal failure of the library */ 349 if (hba_ptr->device_path[0] != '\0') { 350 log(LOG_DEBUG, ROUTINE, 351 "Internal failure: Adapter %s contains no " 352 "port data", hba_ptr->device_path); 353 } else { 354 log(LOG_DEBUG, ROUTINE, 355 "Internal failure: Adapter at index %d contains " 356 " no support data", hba_ptr->index); 357 } 358 unlock(&open_handles_lock); 359 unlock(&all_hbas_lock); 360 return (pwwn); /* zero WWN */ 361 } 362 /* Set the WWN now and return it */ 363 pwwn = hba_ptr->first_port->port_attributes.PortSpecificAttribute.\ 364 SASPort->LocalSASAddress; 365 unlock(&open_handles_lock); 366 unlock(&all_hbas_lock); 367 368 return (pwwn); 369 } 370 371 u_longlong_t 372 wwnConversion(uchar_t *wwn) 373 { 374 u_longlong_t tmp; 375 (void) memcpy(&tmp, wwn, sizeof (u_longlong_t)); 376 tmp = ntohll(tmp); 377 return (tmp); 378 } 379 380 /* 381 * Using ioctl to send uscsi command out 382 */ 383 HBA_STATUS 384 send_uscsi_cmd(const char *devpath, struct uscsi_cmd *ucmd) 385 { 386 const char ROUTINE[] = "send_uscsi_cmd"; 387 int fd; 388 HBA_STATUS ret; 389 390 /* set default timeout to 200 */ 391 ucmd->uscsi_timeout = 200; 392 393 /* reset errno. */ 394 errno = 0; 395 if ((fd = open(devpath, O_RDONLY | O_NDELAY)) == -1) { 396 log(LOG_DEBUG, ROUTINE, 397 "open devpath %s failed: %s", devpath, strerror(errno)); 398 return (HBA_STATUS_ERROR); 399 } 400 401 if (ioctl(fd, USCSICMD, ucmd) == -1) { 402 if (errno == EBUSY) { 403 ret = HBA_STATUS_ERROR_BUSY; 404 } else if (errno == EAGAIN) { 405 ret = HBA_STATUS_ERROR_TRY_AGAIN; 406 } else { 407 ret = HBA_STATUS_ERROR; 408 } 409 log(LOG_DEBUG, ROUTINE, 410 "ioctl send uscsi to devpath: %s failed: %s", 411 devpath, strerror(errno)); 412 (void) close(fd); 413 return (ret); 414 } 415 416 (void) close(fd); 417 418 return (HBA_STATUS_OK); 419 } 420 421 /* 422 * Check whether the given Domain Address is valid. 423 */ 424 HBA_STATUS 425 validateDomainAddress(struct sun_sas_port *hba_port_ptr, HBA_WWN DomainAddr) 426 { 427 if (hba_port_ptr->first_phy != NULL && 428 wwnConversion(hba_port_ptr->first_phy-> 429 phy.domainPortWWN.wwn) == 430 wwnConversion(DomainAddr.wwn)) { 431 return (HBA_STATUS_OK); 432 } 433 return (HBA_STATUS_ERROR); 434 } 435