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                         default:
 281                                 if (loop > DEADLOCK_WARNING) {
 282                                         log(LOG_DEBUG, ROUTINE,
 283                                             "Lock failed: %s 0x%x",
 284                                             strerror(status), mp);
 285                                         break;
 286                                 }
 287                 }
 288 
 289                 if (status) {
 290                         (void) sleep(LOCK_SLEEP);
 291                 }
 292 
 293         } while (status);
 294 }
 295 
 296 /*
 297  * Unlock a mutex lock.
 298  */
 299 void
 300 unlock(mutex_t *mp)
 301 {
 302         (void) mutex_unlock(mp);
 303 }
 304 
 305 
 306 /*
 307  * Get the Port WWN of the first adapter port.  This routine
 308  * is used by the old V1 interfaces so that they can call
 309  * the new V2 interfaces and exhibit the same behavior.
 310  * In the event of error the WWN will be zero.
 311  *
 312  * This function will transition to PAA state but it will not
 313  * verfiy whether data is stale or not
 314  */
 315 HBA_WWN
 316 getFirstAdapterPortWWN(HBA_HANDLE handle)
 317 {
 318         const char      ROUTINE[] = "getFirstAdapterPortWWN";
 319         HBA_WWN                 pwwn = {0, 0, 0, 0, 0, 0, 0, 0};
 320         struct sun_sas_hba      *hba_ptr = NULL;
 321         int                     index = 0;
 322         HBA_STATUS              status;
 323 
 324         lock(&all_hbas_lock);
 325         index = RetrieveIndex(handle);
 326         lock(&open_handles_lock);
 327         hba_ptr = RetrieveHandle(index);
 328         if (hba_ptr == NULL) {
 329                 log(LOG_DEBUG, ROUTINE, "Invalid handle %08lx", handle);
 330                 unlock(&open_handles_lock);
 331                 unlock(&all_hbas_lock);
 332                 return (pwwn); /* zero WWN */
 333         }
 334 
 335         /* Check for stale data */
 336         status = verifyAdapter(hba_ptr);
 337         if (status != HBA_STATUS_OK) {
 338                 log(LOG_DEBUG, ROUTINE, "Verify adapter failed");
 339                 unlock(&open_handles_lock);
 340                 unlock(&all_hbas_lock);
 341                 return (pwwn);
 342         }
 343 
 344         if (hba_ptr->first_port == NULL) {
 345                 /* This is probably an internal failure of the library */
 346                 if (hba_ptr->device_path) {
 347                         log(LOG_DEBUG, ROUTINE,
 348                             "Internal failure:  Adapter %s contains no "
 349                             "port data", hba_ptr->device_path);
 350                 } else {
 351                         log(LOG_DEBUG, ROUTINE,
 352                             "Internal failure:  Adapter at index %d contains "
 353                             " no support data", hba_ptr->index);
 354                 }
 355                 unlock(&open_handles_lock);
 356                 unlock(&all_hbas_lock);
 357                 return (pwwn); /* zero WWN */
 358         }
 359         /* Set the WWN now and return it */
 360         pwwn = hba_ptr->first_port->port_attributes.PortSpecificAttribute.\
 361             SASPort->LocalSASAddress;
 362         unlock(&open_handles_lock);
 363         unlock(&all_hbas_lock);
 364 
 365         return (pwwn);
 366 }
 367 
 368 u_longlong_t
 369 wwnConversion(uchar_t *wwn)
 370 {
 371         u_longlong_t tmp;
 372         (void) memcpy(&tmp, wwn, sizeof (u_longlong_t));
 373         tmp = ntohll(tmp);
 374         return (tmp);
 375 }
 376 
 377 /*
 378  * Using ioctl to send uscsi command out
 379  */
 380 HBA_STATUS
 381 send_uscsi_cmd(const char *devpath, struct uscsi_cmd *ucmd)
 382 {
 383         const char      ROUTINE[] = "send_uscsi_cmd";
 384         int             fd;
 385         HBA_STATUS      ret;
 386 
 387         /* set default timeout to 200 */
 388         ucmd->uscsi_timeout = 200;
 389 
 390         /* reset errno. */
 391         errno = 0;
 392         if ((fd = open(devpath, O_RDONLY | O_NDELAY)) == -1) {
 393                 log(LOG_DEBUG, ROUTINE,
 394                     "open devpath %s failed: %s", devpath, strerror(errno));
 395                 return (HBA_STATUS_ERROR);
 396         }
 397 
 398         if (ioctl(fd, USCSICMD, ucmd) == -1) {
 399                 if (errno == EBUSY) {
 400                         ret = HBA_STATUS_ERROR_BUSY;
 401                 } else if (errno == EAGAIN) {
 402                         ret = HBA_STATUS_ERROR_TRY_AGAIN;
 403                 } else {
 404                         ret = HBA_STATUS_ERROR;
 405                 }
 406                 log(LOG_DEBUG, ROUTINE,
 407                     "ioctl send uscsi to devpath: %s failed: %s",
 408                     devpath, strerror(errno));
 409                 (void) close(fd);
 410                 return (ret);
 411         }
 412 
 413         (void) close(fd);
 414 
 415         return (HBA_STATUS_OK);
 416 }
 417 
 418 /*
 419  * Check whether the given Domain Address is valid.
 420  */
 421 HBA_STATUS
 422 validateDomainAddress(struct sun_sas_port *hba_port_ptr, HBA_WWN DomainAddr)
 423 {
 424         if (hba_port_ptr->first_phy != NULL &&
 425             wwnConversion(hba_port_ptr->first_phy->
 426             phy.domainPortWWN.wwn) ==
 427             wwnConversion(DomainAddr.wwn)) {
 428                 return (HBA_STATUS_OK);
 429         }
 430         return (HBA_STATUS_ERROR);
 431 }