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