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 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); 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) sprintf(pattern_buffer, "Emulex. We network storage. " 220 "Emulex. We network storage. Emulex. We network storage. " 221 "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 MAILBOX *mb; 299 MATCHMAP *mp; 300 MATCHMAP *mp1; 301 uint32_t i; 302 uint8_t *inptr; 303 uint8_t *outptr; 304 int32_t rval = FC_SUCCESS; 305 uint32_t *lptr; 306 307 mp1 = 0; 308 mb = 0; 309 310 /* Check if device is ready */ 311 if (hba->state < FC_LINK_DOWN) { 312 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 313 "BIU: HBA not ready."); 314 315 return (FC_TRAN_BUSY); 316 } 317 318 /* 319 * Get a buffer which will be used for the mailbox command 320 */ 321 if ((mb = (MAILBOX *) emlxs_mem_get(hba, MEM_MBOX | MEM_PRI)) == 0) { 322 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 323 "BIU: Mailbox allocation failed."); 324 325 rval = FC_NOMEM; 326 goto done; 327 } 328 329 /* 330 * Setup and issue mailbox RUN BIU DIAG command Setup test buffers 331 */ 332 if (((mp = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF | MEM_PRI)) == 0) || 333 ((mp1 = (MATCHMAP *) emlxs_mem_get(hba, MEM_BUF | MEM_PRI)) == 0)) { 334 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 335 "BIU: Buffer allocation failed."); 336 337 rval = FC_NOMEM; 338 goto done; 339 } 340 341 if (pattern) { 342 /* Fill the transmit buffer with the pattern */ 343 lptr = (uint32_t *)mp->virt; 344 345 for (i = 0; i < MEM_ELSBUF_SIZE; i += 4) { 346 *lptr++ = pattern; 347 } 348 } else { 349 /* Copy the default pattern into the trasmit buffer */ 350 bcopy((caddr_t)&emlxs_diag_pattern[0], (caddr_t)mp->virt, 351 MEM_ELSBUF_SIZE); 352 } 353 emlxs_mpdata_sync(mp->dma_handle, 0, MEM_ELSBUF_SIZE, 354 DDI_DMA_SYNC_FORDEV); 355 356 bzero(mp1->virt, MEM_ELSBUF_SIZE); 357 emlxs_mpdata_sync(mp1->dma_handle, 0, MEM_ELSBUF_SIZE, 358 DDI_DMA_SYNC_FORDEV); 359 360 /* Create the biu diag request */ 361 (void) emlxs_mb_run_biu_diag(hba, mb, mp->phys, mp1->phys); 362 363 rval = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 60); 364 365 if (rval == MBX_TIMEOUT) { 366 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg, 367 "BUI diagnostic timed out."); 368 369 rval = EMLXS_TEST_FAILED; 370 goto done; 371 } 372 373 emlxs_mpdata_sync(mp1->dma_handle, 0, MEM_ELSBUF_SIZE, 374 DDI_DMA_SYNC_FORKERNEL); 375 376 outptr = mp->virt; 377 inptr = mp1->virt; 378 379 for (i = 0; i < MEM_ELSBUF_SIZE; i++, outptr++, inptr++) { 380 if (*outptr != *inptr) { 381 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_failed_msg, 382 "Data miscompare. Offset %d value %02x should " 383 "be %02x.", i, *inptr, *outptr); 384 385 rval = EMLXS_TEST_FAILED; 386 goto done; 387 } 388 } 389 390 /* Wait half second before returning */ 391 delay(drv_usectohz(500000)); 392 rval = FC_SUCCESS; 393 394 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_biu_complete_msg, "Status Good."); 395 396 done: 397 398 if (mp) { 399 (void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp); 400 } 401 if (mp1) { 402 (void) emlxs_mem_put(hba, MEM_BUF, (uint8_t *)mp1); 403 } 404 if (mb) { 405 (void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mb); 406 } 407 408 return (rval); 409 410 } /* emlxs_diag_biu_run() */ 411 412 413 extern uint32_t 414 emlxs_diag_post_run(emlxs_hba_t *hba) 415 { 416 emlxs_port_t *port = &PPORT; 417 uint32_t rval = FC_SUCCESS; 418 419 if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) { 420 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 421 "POST: HBA shutdown."); 422 423 return (FC_TRAN_BUSY); 424 } 425 426 /* Take board offline */ 427 if ((rval = emlxs_offline(hba))) { 428 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg, 429 "Unable to take adapter offline."); 430 431 rval = FC_RESETFAIL; 432 } 433 434 /* Restart the adapter */ 435 rval = emlxs_sli_hba_reset(hba, 1, 1); 436 437 switch (rval) { 438 case 0: 439 440 (void) emlxs_online(hba); 441 442 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_complete_msg, 443 "Status good."); 444 445 rval = FC_SUCCESS; 446 447 break; 448 449 case 1: /* failed */ 450 451 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_post_failed_msg, 452 "HBA reset failed."); 453 454 rval = FC_RESETFAIL; 455 456 break; 457 458 459 case 2: /* failed */ 460 461 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_diag_error_msg, 462 "HBA busy. Quiece and retry."); 463 464 rval = FC_STATEC_BUSY; 465 466 break; 467 468 } 469 470 return (rval); 471 472 } /* emlxs_diag_post_run() */ 473 474 475 /* ARGSUSED */ 476 extern uint32_t 477 emlxs_core_size(emlxs_hba_t *hba) 478 { 479 480 return (256); 481 482 483 484 } /* emlxs_core_size() */ 485 486 487 /* ARGSUSED */ 488 extern uint32_t 489 emlxs_core_dump(emlxs_hba_t *hba, char *buffer, uint32_t size) 490 { 491 uint32_t i; 492 493 bzero(buffer, size); 494 495 /* Fill the buffer with dummy data */ 496 for (i = 0; i < 256; i++) { 497 buffer[i] = (char)(i & 0xff); 498 } 499 return (FC_SUCCESS); 500 501 502 503 } /* emlxs_core_dump() */ 504