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