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-2011 Emulex. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <emlxs.h> 28 29 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 30 EMLXS_MSG_DEF(EMLXS_PKT_C); 31 32 #if (EMLXS_MODREV >= EMLXS_MODREV3) 33 typedef struct 34 { 35 ddi_dma_cookie_t pkt_cmd_cookie; 36 ddi_dma_cookie_t pkt_resp_cookie; 37 ddi_dma_cookie_t pkt_data_cookie; 38 39 } emlxs_pkt_cookie_t; 40 #endif /* >= EMLXS_MODREV3 */ 41 42 43 /* ARGSUSED */ 44 static void 45 emlxs_pkt_thread(emlxs_hba_t *hba, void *arg1, void *arg2) 46 { 47 emlxs_port_t *port; 48 fc_packet_t *pkt = (fc_packet_t *)arg1; 49 int32_t rval; 50 emlxs_buf_t *sbp; 51 52 sbp = PKT2PRIV(pkt); 53 port = sbp->port; 54 55 /* Send the pkt now */ 56 rval = emlxs_pkt_send(pkt, 1); 57 58 if (rval != FC_SUCCESS) { 59 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_pkt_trans_msg, 60 "Deferred pkt_send failed: status=%x pkt=%p", rval, 61 pkt); 62 63 if (pkt->pkt_comp) { 64 emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT, 0, 1); 65 66 ((CHANNEL *)sbp->channel)->ulpCmplCmd++; 67 (*pkt->pkt_comp) (pkt); 68 } else { 69 emlxs_pkt_free(pkt); 70 } 71 } 72 73 return; 74 75 } /* emlxs_pkt_thread() */ 76 77 78 extern int32_t 79 emlxs_pkt_send(fc_packet_t *pkt, uint32_t now) 80 { 81 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private; 82 emlxs_hba_t *hba = HBA; 83 int32_t rval; 84 85 if (now) { 86 rval = emlxs_fca_transport((opaque_t)port, pkt); 87 } else { 88 /* Spawn a thread to send the pkt */ 89 emlxs_thread_spawn(hba, emlxs_pkt_thread, (char *)pkt, NULL); 90 91 rval = FC_SUCCESS; 92 } 93 94 return (rval); 95 96 } /* emlxs_pkt_send() */ 97 98 99 extern void 100 emlxs_pkt_free(fc_packet_t *pkt) 101 { 102 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private; 103 104 (void) emlxs_fca_pkt_uninit((opaque_t)port, pkt); 105 106 if (pkt->pkt_datalen) { 107 (void) ddi_dma_unbind_handle(pkt->pkt_data_dma); 108 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 109 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 110 } 111 112 if (pkt->pkt_rsplen) { 113 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 114 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 115 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 116 } 117 118 if (pkt->pkt_cmdlen) { 119 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 120 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 121 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 122 } 123 #if (EMLXS_MODREV >= EMLXS_MODREV3) 124 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t) + 125 sizeof (emlxs_pkt_cookie_t))); 126 #else 127 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t))); 128 #endif /* >= EMLXS_MODREV3 */ 129 130 return; 131 132 } /* emlxs_pkt_free() */ 133 134 135 /* Default pkt callback routine */ 136 extern void 137 emlxs_pkt_callback(fc_packet_t *pkt) 138 { 139 emlxs_pkt_free(pkt); 140 141 return; 142 143 } /* emlxs_pkt_callback() */ 144 145 146 147 extern fc_packet_t * 148 emlxs_pkt_alloc(emlxs_port_t *port, uint32_t cmdlen, uint32_t rsplen, 149 uint32_t datalen, int32_t sleep) 150 { 151 emlxs_hba_t *hba = HBA; 152 fc_packet_t *pkt; 153 int32_t(*cb) (caddr_t); 154 unsigned long real_len; 155 uint32_t pkt_size; 156 emlxs_buf_t *sbp; 157 158 #if (EMLXS_MODREV >= EMLXS_MODREV3) 159 emlxs_pkt_cookie_t *pkt_cookie; 160 161 pkt_size = 162 sizeof (fc_packet_t) + sizeof (emlxs_buf_t) + 163 sizeof (emlxs_pkt_cookie_t); 164 #else 165 uint32_t num_cookie; 166 167 pkt_size = sizeof (fc_packet_t) + sizeof (emlxs_buf_t); 168 #endif /* >= EMLXS_MODREV3 */ 169 170 171 /* Allocate some space */ 172 if (!(pkt = (fc_packet_t *)kmem_alloc(pkt_size, sleep))) { 173 return (NULL); 174 } 175 176 bzero(pkt, pkt_size); 177 178 cb = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 179 180 pkt->pkt_ulp_private = (opaque_t)port; 181 pkt->pkt_fca_private = 182 (opaque_t)((uintptr_t)pkt + sizeof (fc_packet_t)); 183 pkt->pkt_comp = emlxs_pkt_callback; 184 pkt->pkt_tran_flags = (FC_TRAN_CLASS3 | FC_TRAN_INTR); 185 pkt->pkt_cmdlen = cmdlen; 186 pkt->pkt_rsplen = rsplen; 187 pkt->pkt_datalen = datalen; 188 189 #if (EMLXS_MODREV >= EMLXS_MODREV3) 190 pkt_cookie = 191 (emlxs_pkt_cookie_t *)((uintptr_t)pkt + sizeof (fc_packet_t) + 192 sizeof (emlxs_buf_t)); 193 pkt->pkt_cmd_cookie = &pkt_cookie->pkt_cmd_cookie; 194 pkt->pkt_resp_cookie = &pkt_cookie->pkt_resp_cookie; 195 pkt->pkt_data_cookie = &pkt_cookie->pkt_data_cookie; 196 #endif /* >= EMLXS_MODREV3 */ 197 198 if (cmdlen) { 199 /* Allocate the cmd buf */ 200 if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg, cb, 201 NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) { 202 cmdlen = 0; 203 rsplen = 0; 204 datalen = 0; 205 goto failed; 206 } 207 208 if (ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmdlen, 209 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL, 210 (caddr_t *)&pkt->pkt_cmd, &real_len, 211 &pkt->pkt_cmd_acc) != DDI_SUCCESS) { 212 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 213 214 cmdlen = 0; 215 rsplen = 0; 216 datalen = 0; 217 goto failed; 218 } 219 220 if (real_len < cmdlen) { 221 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 222 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 223 224 cmdlen = 0; 225 rsplen = 0; 226 datalen = 0; 227 goto failed; 228 } 229 #if (EMLXS_MODREV >= EMLXS_MODREV3) 230 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 231 pkt->pkt_cmd, real_len, 232 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL, 233 pkt->pkt_cmd_cookie, 234 &pkt->pkt_cmd_cookie_cnt) != DDI_DMA_MAPPED) 235 #else 236 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 237 pkt->pkt_cmd, real_len, 238 DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, NULL, 239 &pkt->pkt_cmd_cookie, &num_cookie) != DDI_DMA_MAPPED) 240 #endif /* >= EMLXS_MODREV3 */ 241 { 242 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 243 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 244 245 cmdlen = 0; 246 rsplen = 0; 247 datalen = 0; 248 goto failed; 249 } 250 #if (EMLXS_MODREV >= EMLXS_MODREV3) 251 if (pkt->pkt_cmd_cookie_cnt != 1) 252 #else 253 if (num_cookie != 1) 254 #endif /* >= EMLXS_MODREV3 */ 255 { 256 rsplen = 0; 257 datalen = 0; 258 goto failed; 259 } 260 261 bzero(pkt->pkt_cmd, cmdlen); 262 263 } 264 265 if (rsplen) { 266 /* Allocate the rsp buf */ 267 if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg, cb, 268 NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) { 269 rsplen = 0; 270 datalen = 0; 271 goto failed; 272 273 } 274 275 if (ddi_dma_mem_alloc(pkt->pkt_resp_dma, rsplen, 276 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL, 277 (caddr_t *)&pkt->pkt_resp, &real_len, 278 &pkt->pkt_resp_acc) != DDI_SUCCESS) { 279 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 280 281 rsplen = 0; 282 datalen = 0; 283 goto failed; 284 } 285 286 if (real_len < rsplen) { 287 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 288 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 289 290 rsplen = 0; 291 datalen = 0; 292 goto failed; 293 } 294 #if (EMLXS_MODREV >= EMLXS_MODREV3) 295 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 296 pkt->pkt_resp, real_len, 297 DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL, 298 pkt->pkt_resp_cookie, 299 &pkt->pkt_resp_cookie_cnt) != DDI_DMA_MAPPED) 300 #else 301 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 302 pkt->pkt_resp, real_len, 303 DDI_DMA_READ | DDI_DMA_CONSISTENT, cb, NULL, 304 &pkt->pkt_resp_cookie, &num_cookie) != DDI_DMA_MAPPED) 305 #endif /* >= EMLXS_MODREV3 */ 306 { 307 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 308 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 309 310 rsplen = 0; 311 datalen = 0; 312 goto failed; 313 } 314 #if (EMLXS_MODREV >= EMLXS_MODREV3) 315 if (pkt->pkt_resp_cookie_cnt != 1) 316 #else 317 if (num_cookie != 1) 318 #endif /* >= EMLXS_MODREV3 */ 319 { 320 datalen = 0; 321 goto failed; 322 } 323 324 bzero(pkt->pkt_resp, rsplen); 325 326 } 327 328 /* Allocate the data buf */ 329 if (datalen) { 330 /* Allocate the rsp buf */ 331 if (ddi_dma_alloc_handle(hba->dip, &hba->dma_attr_1sg, cb, 332 NULL, &pkt->pkt_data_dma) != DDI_SUCCESS) { 333 datalen = 0; 334 goto failed; 335 } 336 337 if (ddi_dma_mem_alloc(pkt->pkt_data_dma, datalen, 338 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL, 339 (caddr_t *)&pkt->pkt_data, &real_len, 340 &pkt->pkt_data_acc) != DDI_SUCCESS) { 341 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 342 343 datalen = 0; 344 goto failed; 345 } 346 347 if (real_len < datalen) { 348 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 349 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 350 351 datalen = 0; 352 goto failed; 353 } 354 #if (EMLXS_MODREV >= EMLXS_MODREV3) 355 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL, 356 pkt->pkt_data, real_len, 357 DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, 358 NULL, pkt->pkt_data_cookie, 359 &pkt->pkt_data_cookie_cnt) != DDI_DMA_MAPPED) 360 #else 361 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL, 362 pkt->pkt_data, real_len, 363 DDI_DMA_READ | DDI_DMA_WRITE | DDI_DMA_CONSISTENT, cb, 364 NULL, &pkt->pkt_data_cookie, 365 &num_cookie) != DDI_DMA_MAPPED) 366 #endif /* >= EMLXS_MODREV3 */ 367 { 368 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 369 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 370 371 datalen = 0; 372 goto failed; 373 } 374 #if (EMLXS_MODREV >= EMLXS_MODREV3) 375 if (pkt->pkt_data_cookie_cnt != 1) 376 #else 377 if (num_cookie != 1) 378 #endif /* >= EMLXS_MODREV3 */ 379 { 380 goto failed; 381 } 382 383 bzero(pkt->pkt_data, datalen); 384 } 385 386 sbp = PKT2PRIV(pkt); 387 bzero((void *)sbp, sizeof (emlxs_buf_t)); 388 389 mutex_init(&sbp->mtx, NULL, MUTEX_DRIVER, DDI_INTR_PRI(hba->intr_arg)); 390 sbp->pkt_flags = PACKET_VALID | PACKET_ULP_OWNED | PACKET_ALLOCATED; 391 sbp->port = port; 392 sbp->pkt = pkt; 393 sbp->iocbq.sbp = sbp; 394 395 return (pkt); 396 397 failed: 398 399 if (datalen) { 400 (void) ddi_dma_unbind_handle(pkt->pkt_data_dma); 401 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 402 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 403 } 404 405 if (rsplen) { 406 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 407 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 408 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 409 } 410 411 if (cmdlen) { 412 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 413 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 414 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 415 } 416 417 if (pkt) { 418 kmem_free(pkt, pkt_size); 419 } 420 421 return (NULL); 422 423 } /* emlxs_pkt_alloc() */ 424