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