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