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 9 * http://www.opensource.org/licenses/cddl1.txt. 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 (c) 2004-2012 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <emlxs.h> 28 29 30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 31 EMLXS_MSG_DEF(EMLXS_DIAG_C); 32 33 uint32_t emlxs_diag_pattern[256] = { 34 /* Walking ones */ 35 0x80000000, 0x40000000, 0x20000000, 0x10000000, 36 0x08000000, 0x04000000, 0x02000000, 0x01000000, 37 0x00800000, 0x00400000, 0x00200000, 0x00100000, 38 0x00080000, 0x00040000, 0x00020000, 0x00010000, 39 0x00008000, 0x00004000, 0x00002000, 0x00001000, 40 0x00000800, 0x00000400, 0x00000200, 0x00000100, 41 0x00000080, 0x00000040, 0x00000020, 0x00000010, 42 0x00000008, 0x00000004, 0x00000002, 0x00000001, 43 44 /* Walking zeros */ 45 0x7fffffff, 0xbfffffff, 0xdfffffff, 0xefffffff, 46 0xf7ffffff, 0xfbffffff, 0xfdffffff, 0xfeffffff, 47 0xff7fffff, 0xffbfffff, 0xffdfffff, 0xffefffff, 48 0xfff7ffff, 0xfffbffff, 0xfffdffff, 0xfffeffff, 49 0xffff7fff, 0xffffbfff, 0xffffdfff, 0xffffefff, 50 0xfffff7ff, 0xfffffbff, 0xfffffdff, 0xfffffeff, 51 0xffffff7f, 0xffffffbf, 0xffffffdf, 0xffffffef, 52 0xfffffff7, 0xfffffffb, 0xfffffffd, 0xfffffffe, 53 54 /* all zeros */ 55 0x00000000, 0x00000000, 0x00000000, 0x00000000, 56 0x00000000, 0x00000000, 0x00000000, 0x00000000, 57 0x00000000, 0x00000000, 0x00000000, 0x00000000, 58 0x00000000, 0x00000000, 0x00000000, 0x00000000, 59 0x00000000, 0x00000000, 0x00000000, 0x00000000, 60 0x00000000, 0x00000000, 0x00000000, 0x00000000, 61 0x00000000, 0x00000000, 0x00000000, 0x00000000, 62 0x00000000, 0x00000000, 0x00000000, 0x00000000, 63 64 /* all ones */ 65 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 66 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 67 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 68 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 69 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 70 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 71 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 72 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 73 74 /* all 5's */ 75 0x55555555, 0x55555555, 0x55555555, 0x55555555, 76 0x55555555, 0x55555555, 0x55555555, 0x55555555, 77 0x55555555, 0x55555555, 0x55555555, 0x55555555, 78 0x55555555, 0x55555555, 0x55555555, 0x55555555, 79 0x55555555, 0x55555555, 0x55555555, 0x55555555, 80 0x55555555, 0x55555555, 0x55555555, 0x55555555, 81 0x55555555, 0x55555555, 0x55555555, 0x55555555, 82 0x55555555, 0x55555555, 0x55555555, 0x55555555, 83 84 /* all a's */ 85 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 86 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 87 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 88 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 89 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 90 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 91 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 92 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 0xaaaaaaaa, 93 94 /* all 5a's */ 95 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 96 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 97 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 98 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 99 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 100 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 101 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 102 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 0x5a5a5a5a, 103 104 /* all a5's */ 105 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 106 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 107 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 108 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 109 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 110 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 111 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 112 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5, 0xa5a5a5a5 113 }; 114 115 116 /* Default pkt callback routine */ 117 static void 118 emlxs_diag_pkt_callback(fc_packet_t *pkt) 119 { 120 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private; 121 122 /* Set the completed flag and wake up sleeping threads */ 123 mutex_enter(&EMLXS_PKT_LOCK); 124 pkt->pkt_tran_flags |= FC_TRAN_COMPLETED; 125 cv_broadcast(&EMLXS_PKT_CV); 126 mutex_exit(&EMLXS_PKT_LOCK); 127 128 return; 129 130 } /* emlxs_diag_pkt_callback() */ 131 132 133 extern uint32_t 134 emlxs_diag_echo_run(emlxs_port_t *port, uint32_t did, uint32_t pattern) 135 { 136 emlxs_hba_t *hba = HBA; 137 uint32_t i = 0; 138 uint32_t rval = FC_SUCCESS; 139 int32_t pkt_ret; 140 fc_packet_t *pkt; 141 ELS_PKT *els; 142 clock_t timeout; 143 uint8_t *pkt_resp; 144 char *pattern_buffer; 145 uint32_t length; 146 uint32_t *lptr; 147 NODELIST *ndlp; 148 uint8_t *pat; 149 150 /* Check did */ 151 if (did == 0) { 152 did = port->did; 153 } 154 155 /* Check if device is ready */ 156 if ((hba->state < FC_LINK_UP) || (port->did == 0)) { 157 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 158 "ECHO: HBA not ready."); 159 160 return (FC_TRAN_BUSY); 161 } 162 163 /* Check for the host node */ 164 ndlp = emlxs_node_find_did(port, port->did, 1); 165 166 if (!ndlp || !ndlp->nlp_active) { 167 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 168 "ECHO: HBA not ready."); 169 170 return (FC_TRAN_BUSY); 171 } 172 173 length = 124; 174 175 /* Prepare ECHO pkt */ 176 if (!(pkt = emlxs_pkt_alloc(port, sizeof (uint32_t) + length, 177 sizeof (uint32_t) + length, 0, KM_NOSLEEP))) { 178 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 179 "ECHO: Unable to allocate packet. size=%x", 180 sizeof (uint32_t) + length); 181 182 return (FC_NOMEM); 183 } 184 185 /* pkt initialization */ 186 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 187 pkt->pkt_timeout = 60; 188 189 /* Build the fc header */ 190 pkt->pkt_cmd_fhdr.d_id = did; 191 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | R_CTL_UNSOL_CONTROL; 192 pkt->pkt_cmd_fhdr.s_id = port->did; 193 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 194 pkt->pkt_cmd_fhdr.f_ctl = 195 F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE | F_CTL_END_SEQ; 196 pkt->pkt_cmd_fhdr.seq_id = 0; 197 pkt->pkt_cmd_fhdr.df_ctl = 0; 198 pkt->pkt_cmd_fhdr.seq_cnt = 0; 199 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 200 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 201 pkt->pkt_cmd_fhdr.ro = 0; 202 pkt->pkt_comp = emlxs_diag_pkt_callback; 203 204 /* Build the command */ 205 els = (ELS_PKT *) pkt->pkt_cmd; 206 els->elsCode = 0x10; 207 pattern_buffer = (char *)els->un.pad; 208 209 if (pattern) { 210 /* Fill the transmit buffer with the pattern */ 211 lptr = (uint32_t *)pattern_buffer; 212 213 for (i = 0; i < length; i += 4) { 214 *lptr++ = pattern; 215 } 216 } else { 217 /* Program the default echo pattern */ 218 bzero(pattern_buffer, length); 219 (void) snprintf(pattern_buffer, length, 220 "Emulex. We network storage. Emulex. We network storage. " 221 "Emulex. We network storage. Emulex. We network storage."); 222 } 223 224 /* Send ECHO pkt */ 225 if ((rval = emlxs_pkt_send(pkt, 1)) != FC_SUCCESS) { 226 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 227 "ECHO: Packet send failed."); 228 229 goto done; 230 } 231 232 /* Wait for ECHO completion */ 233 mutex_enter(&EMLXS_PKT_LOCK); 234 timeout = emlxs_timeout(hba, (pkt->pkt_timeout + 15)); 235 pkt_ret = 0; 236 while ((pkt_ret != -1) && !(pkt->pkt_tran_flags & FC_TRAN_COMPLETED)) { 237 pkt_ret = 238 cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK, timeout); 239 240 } 241 mutex_exit(&EMLXS_PKT_LOCK); 242 243 if (pkt_ret == -1) { 244 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg, 245 "Packet timed out."); 246 247 return (FC_ABORTED); 248 } 249 250 if (pkt->pkt_state != FC_PKT_SUCCESS) { 251 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg, 252 "Transport error."); 253 254 rval = FC_TRANSPORT_ERROR; 255 goto done; 256 } 257 258 /* Check response payload */ 259 pkt_resp = (uint8_t *)pkt->pkt_resp + 4; 260 pat = (uint8_t *)pattern_buffer; 261 rval = FC_SUCCESS; 262 263 for (i = 0; i < length; i++, pkt_resp++, pat++) { 264 if (*pkt_resp != *pat) { 265 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_failed_msg, 266 "Data miscompare. did=%06x length=%d. Offset %d " 267 "value %02x should be %02x.", did, length, i, 268 *pkt_resp, *pat); 269 270 rval = EMLXS_TEST_FAILED; 271 272 break; 273 } 274 } 275 276 if (rval == FC_SUCCESS) { 277 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_echo_complete_msg, 278 "did=%06x length=%d pattern=%02x,%02x,%02x,%02x...", 279 did, length, pattern_buffer[0] & 0xff, 280 pattern_buffer[1] & 0xff, pattern_buffer[2] & 0xff, 281 pattern_buffer[3] & 0xff); 282 } 283 284 done: 285 286 /* Free the echo pkt */ 287 emlxs_pkt_free(pkt); 288 289 return (rval); 290 291 } /* emlxs_diag_echo_run() */ 292 293 294 extern uint32_t 295 emlxs_diag_biu_run(emlxs_hba_t *hba, uint32_t pattern) 296 { 297 emlxs_port_t *port = &PPORT; 298 MAILBOXQ *mbq = NULL; 299 MATCHMAP *mp = NULL; 300 MATCHMAP *mp1 = NULL; 301 uint32_t i; 302 uint8_t *inptr; 303 uint8_t *outptr; 304 int32_t rval = FC_SUCCESS; 305 uint32_t *lptr; 306 307 /* Check if device is ready */ 308 if (hba->state < FC_LINK_DOWN) { 309 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 310 "BIU: HBA not ready."); 311 312 return (FC_TRAN_BUSY); 313 } 314 315 /* 316 * Get a buffer which will be used for the mailbox command 317 */ 318 if ((mbq = (MAILBOXQ *) emlxs_mem_get(hba, MEM_MBOX)) == 0) { 319 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 320 "BIU: Mailbox allocation failed."); 321 322 rval = FC_NOMEM; 323 goto done; 324 } 325 326 /* 327 * Setup and issue mailbox RUN BIU DIAG command Setup test buffers 328 */ 329 if (((mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF)) == 0) || 330 ((mp1 = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF)) == 0)) { 331 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 332 "BIU: Buffer allocation failed."); 333 334 rval = FC_NOMEM; 335 goto done; 336 } 337 338 if (pattern) { 339 /* Fill the transmit buffer with the pattern */ 340 lptr = (uint32_t *)mp->virt; 341 342 for (i = 0; i < MEM_ELSBUF_SIZE; i += 4) { 343 *lptr++ = pattern; 344 } 345 } else { 346 /* Copy the default pattern into the trasmit buffer */ 347 bcopy((caddr_t)&emlxs_diag_pattern[0], (caddr_t)mp->virt, 348 MEM_ELSBUF_SIZE); 349 } 350 EMLXS_MPDATA_SYNC(mp->dma_handle, 0, MEM_ELSBUF_SIZE, 351 DDI_DMA_SYNC_FORDEV); 352 353 bzero(mp1->virt, MEM_ELSBUF_SIZE); 354 EMLXS_MPDATA_SYNC(mp1->dma_handle, 0, MEM_ELSBUF_SIZE, 355 DDI_DMA_SYNC_FORDEV); 356 357 /* Create the biu diag request */ 358 (void) emlxs_mb_run_biu_diag(hba, mbq, mp->phys, mp1->phys); 359 360 rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 60); 361 362 if (rval == MBX_TIMEOUT) { 363 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg, 364 "BUI diagnostic timed out."); 365 366 rval = EMLXS_TEST_FAILED; 367 goto done; 368 } 369 370 EMLXS_MPDATA_SYNC(mp1->dma_handle, 0, MEM_ELSBUF_SIZE, 371 DDI_DMA_SYNC_FORKERNEL); 372 373 outptr = mp->virt; 374 inptr = mp1->virt; 375 376 for (i = 0; i < MEM_ELSBUF_SIZE; i++, outptr++, inptr++) { 377 if (*outptr != *inptr) { 378 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg, 379 "Data miscompare. Offset %d value %02x should " 380 "be %02x.", i, *inptr, *outptr); 381 382 rval = EMLXS_TEST_FAILED; 383 goto done; 384 } 385 } 386 387 /* Wait half second before returning */ 388 delay(drv_usectohz(500000)); 389 rval = FC_SUCCESS; 390 391 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_complete_msg, "Status Good."); 392 393 done: 394 395 if (mp) { 396 #ifdef FMA_SUPPORT 397 if (emlxs_fm_check_dma_handle(hba, mp->dma_handle) 398 != DDI_FM_OK) { 399 EMLXS_MSGF(EMLXS_CONTEXT, 400 &emlxs_invalid_dma_handle_msg, 401 "diag_biu_run: hdl=%p", 402 mp->dma_handle); 403 rval = EMLXS_TEST_FAILED; 404 } 405 #endif /* FMA_SUPPORT */ 406 emlxs_mem_put(hba, MEM_BUF, (void *)mp); 407 } 408 if (mp1) { 409 #ifdef FMA_SUPPORT 410 if (emlxs_fm_check_dma_handle(hba, mp1->dma_handle) 411 != DDI_FM_OK) { 412 EMLXS_MSGF(EMLXS_CONTEXT, 413 &emlxs_invalid_dma_handle_msg, 414 "diag_biu_run: hdl=%p", 415 mp1->dma_handle); 416 rval = EMLXS_TEST_FAILED; 417 } 418 #endif /* FMA_SUPPORT */ 419 emlxs_mem_put(hba, MEM_BUF, (void *)mp1); 420 } 421 if (mbq) { 422 emlxs_mem_put(hba, MEM_MBOX, (void *)mbq); 423 } 424 425 return (rval); 426 427 } /* emlxs_diag_biu_run() */ 428 429 430 extern uint32_t 431 emlxs_diag_post_run(emlxs_hba_t *hba) 432 { 433 emlxs_port_t *port = &PPORT; 434 uint32_t rval = FC_SUCCESS; 435 436 if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) { 437 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 438 "POST: HBA shutdown."); 439 440 return (FC_TRAN_BUSY); 441 } 442 443 /* Take board offline */ 444 if ((rval = emlxs_offline(hba, 0))) { 445 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg, 446 "Unable to take adapter offline."); 447 448 rval = FC_RESETFAIL; 449 } 450 451 /* Restart the adapter */ 452 rval = EMLXS_SLI_HBA_RESET(hba, 1, 1, 0); 453 454 switch (rval) { 455 case 0: 456 457 (void) emlxs_online(hba); 458 459 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_complete_msg, 460 "Status good."); 461 462 rval = FC_SUCCESS; 463 464 break; 465 466 case 1: /* failed */ 467 468 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg, 469 "HBA reset failed."); 470 471 rval = FC_RESETFAIL; 472 473 break; 474 475 476 case 2: /* failed */ 477 478 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 479 "HBA busy. Quiece and retry."); 480 481 rval = FC_STATEC_BUSY; 482 483 break; 484 485 } 486 487 return (rval); 488 489 } /* emlxs_diag_post_run() */ 490