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 /* 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 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 static void 44 emlxs_pkt_thread(void *arg) 45 { 46 /* emlxs_hba_t *hba; */ 47 emlxs_port_t *port; 48 fc_packet_t *pkt = (fc_packet_t *)arg; 49 int32_t rval; 50 emlxs_buf_t *sbp; 51 52 sbp = PKT2PRIV(pkt); 53 port = sbp->port; 54 /* hba = HBA; */ 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", 62 rval, pkt); 63 64 if (pkt->pkt_comp) { 65 emlxs_set_pkt_state(sbp, IOSTAT_LOCAL_REJECT, 0, 1); 66 67 (*pkt->pkt_comp) (pkt); 68 } else { 69 emlxs_pkt_free(pkt); 70 } 71 } 72 return; 73 74 } /* emlxs_pkt_thread() */ 75 76 77 extern int32_t 78 emlxs_pkt_send(fc_packet_t *pkt, uint32_t now) 79 { 80 int32_t rval; 81 82 if (now) { 83 rval = emlxs_transport((opaque_t)pkt->pkt_ulp_private, pkt); 84 } else { 85 /* Spawn a thread to send the pkt */ 86 (void) thread_create(NULL, 0, emlxs_pkt_thread, (char *)pkt, 0, 87 &p0, TS_RUN, v.v_maxsyspri - 2); 88 89 rval = FC_SUCCESS; 90 } 91 92 return (rval); 93 94 } /* emlxs_pkt_send() */ 95 96 97 extern void 98 emlxs_pkt_free(fc_packet_t *pkt) 99 { 100 101 emlxs_port_t *port = (emlxs_port_t *)pkt->pkt_ulp_private; 102 /* emlxs_hba_t *hba = HBA; */ 103 104 (void) emlxs_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 if (pkt->pkt_rsplen) { 112 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 113 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 114 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 115 } 116 if (pkt->pkt_cmdlen) { 117 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 118 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 119 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 120 } 121 #if (EMLXS_MODREV >= EMLXS_MODREV3) 122 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t) + 123 sizeof (emlxs_pkt_cookie_t))); 124 #else 125 kmem_free(pkt, (sizeof (fc_packet_t) + sizeof (emlxs_buf_t))); 126 #endif /* >= EMLXS_MODREV3 */ 127 128 return; 129 130 } /* emlxs_pkt_free() */ 131 132 133 /* Default pkt callback routine */ 134 extern void 135 emlxs_pkt_callback(fc_packet_t *pkt) 136 { 137 emlxs_pkt_free(pkt); 138 139 return; 140 141 } /* emlxs_pkt_callback() */ 142 143 144 145 extern fc_packet_t * 146 emlxs_pkt_alloc(emlxs_port_t *port, uint32_t cmdlen, uint32_t rsplen, 147 uint32_t datalen, int32_t sleep) 148 { 149 emlxs_hba_t *hba = HBA; 150 fc_packet_t *pkt; 151 int32_t(*cb) (caddr_t); 152 unsigned long real_len; 153 uint32_t pkt_size; 154 emlxs_buf_t *sbp; 155 156 #if (EMLXS_MODREV >= EMLXS_MODREV3) 157 emlxs_pkt_cookie_t *pkt_cookie; 158 159 pkt_size = sizeof (fc_packet_t) + sizeof (emlxs_buf_t) + 160 sizeof (emlxs_pkt_cookie_t); 161 #else 162 uint32_t num_cookie; 163 164 pkt_size = sizeof (fc_packet_t) + sizeof (emlxs_buf_t); 165 #endif /* >= EMLXS_MODREV3 */ 166 167 168 /* Allocate some space */ 169 if (!(pkt = (fc_packet_t *)kmem_alloc(pkt_size, sleep))) { 170 return (NULL); 171 } 172 bzero(pkt, pkt_size); 173 174 cb = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP : DDI_DMA_DONTWAIT; 175 176 pkt->pkt_ulp_private = (opaque_t)port; 177 pkt->pkt_fca_private = (opaque_t)((uintptr_t)pkt + 178 sizeof (fc_packet_t)); 179 pkt->pkt_comp = emlxs_pkt_callback; 180 pkt->pkt_tran_flags = (FC_TRAN_CLASS3 | FC_TRAN_INTR); 181 pkt->pkt_cmdlen = cmdlen; 182 pkt->pkt_rsplen = rsplen; 183 pkt->pkt_datalen = datalen; 184 185 #if (EMLXS_MODREV >= EMLXS_MODREV3) 186 pkt_cookie = (emlxs_pkt_cookie_t *)((uintptr_t)pkt + 187 sizeof (fc_packet_t) + sizeof (emlxs_buf_t)); 188 pkt->pkt_cmd_cookie = &pkt_cookie->pkt_cmd_cookie; 189 pkt->pkt_resp_cookie = &pkt_cookie->pkt_resp_cookie; 190 pkt->pkt_data_cookie = &pkt_cookie->pkt_data_cookie; 191 #endif /* >= EMLXS_MODREV3 */ 192 193 if (cmdlen) { 194 /* Allocate the cmd buf */ 195 if (ddi_dma_alloc_handle(hba->dip, &emlxs_dma_attr_1sg, cb, 196 NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) { 197 cmdlen = 0; 198 rsplen = 0; 199 datalen = 0; 200 goto failed; 201 } 202 if (ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmdlen, 203 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL, 204 (caddr_t *)&pkt->pkt_cmd, &real_len, &pkt->pkt_cmd_acc) 205 != DDI_SUCCESS) { 206 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 207 208 cmdlen = 0; 209 rsplen = 0; 210 datalen = 0; 211 goto failed; 212 } 213 if (real_len < cmdlen) { 214 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 215 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 216 217 cmdlen = 0; 218 rsplen = 0; 219 datalen = 0; 220 goto failed; 221 } 222 #if (EMLXS_MODREV >= EMLXS_MODREV3) 223 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 224 pkt->pkt_cmd, real_len, DDI_DMA_WRITE | DDI_DMA_CONSISTENT, 225 cb, NULL, pkt->pkt_cmd_cookie, &pkt->pkt_cmd_cookie_cnt) 226 != DDI_DMA_MAPPED) 227 #else 228 if (ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 229 pkt->pkt_cmd, real_len, DDI_DMA_WRITE | DDI_DMA_CONSISTENT, 230 cb, NULL, &pkt->pkt_cmd_cookie, &num_cookie) 231 != DDI_DMA_MAPPED) 232 #endif /* >= EMLXS_MODREV3 */ 233 { 234 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 235 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 236 237 cmdlen = 0; 238 rsplen = 0; 239 datalen = 0; 240 goto failed; 241 } 242 #if (EMLXS_MODREV >= EMLXS_MODREV3) 243 if (pkt->pkt_cmd_cookie_cnt != 1) 244 #else 245 if (num_cookie != 1) 246 #endif /* >= EMLXS_MODREV3 */ 247 { 248 rsplen = 0; 249 datalen = 0; 250 goto failed; 251 } 252 bzero(pkt->pkt_cmd, cmdlen); 253 254 } 255 if (rsplen) { 256 /* Allocate the rsp buf */ 257 if (ddi_dma_alloc_handle(hba->dip, &emlxs_dma_attr_1sg, cb, 258 NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) { 259 rsplen = 0; 260 datalen = 0; 261 goto failed; 262 263 } 264 if (ddi_dma_mem_alloc(pkt->pkt_resp_dma, rsplen, 265 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL, 266 (caddr_t *)&pkt->pkt_resp, &real_len, &pkt->pkt_resp_acc) 267 != DDI_SUCCESS) { 268 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 269 270 rsplen = 0; 271 datalen = 0; 272 goto failed; 273 } 274 if (real_len < rsplen) { 275 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 276 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 277 278 rsplen = 0; 279 datalen = 0; 280 goto failed; 281 } 282 #if (EMLXS_MODREV >= EMLXS_MODREV3) 283 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 284 pkt->pkt_resp, real_len, DDI_DMA_READ | DDI_DMA_CONSISTENT, 285 cb, NULL, pkt->pkt_resp_cookie, &pkt->pkt_resp_cookie_cnt) 286 != DDI_DMA_MAPPED) 287 #else 288 if (ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 289 pkt->pkt_resp, real_len, DDI_DMA_READ | DDI_DMA_CONSISTENT, 290 cb, NULL, &pkt->pkt_resp_cookie, &num_cookie) 291 != DDI_DMA_MAPPED) 292 #endif /* >= EMLXS_MODREV3 */ 293 { 294 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 295 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 296 297 rsplen = 0; 298 datalen = 0; 299 goto failed; 300 } 301 #if (EMLXS_MODREV >= EMLXS_MODREV3) 302 if (pkt->pkt_resp_cookie_cnt != 1) 303 #else 304 if (num_cookie != 1) 305 #endif /* >= EMLXS_MODREV3 */ 306 { 307 datalen = 0; 308 goto failed; 309 } 310 bzero(pkt->pkt_resp, rsplen); 311 312 } 313 /* Allocate the data buf */ 314 if (datalen) { 315 /* Allocate the rsp buf */ 316 if (ddi_dma_alloc_handle(hba->dip, &emlxs_dma_attr_1sg, cb, 317 NULL, &pkt->pkt_data_dma) != DDI_SUCCESS) { 318 datalen = 0; 319 goto failed; 320 } 321 if (ddi_dma_mem_alloc(pkt->pkt_data_dma, datalen, 322 &emlxs_data_acc_attr, DDI_DMA_CONSISTENT, cb, NULL, 323 (caddr_t *)&pkt->pkt_data, &real_len, &pkt->pkt_data_acc) 324 != DDI_SUCCESS) { 325 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 326 327 datalen = 0; 328 goto failed; 329 } 330 if (real_len < datalen) { 331 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 332 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 333 334 datalen = 0; 335 goto failed; 336 } 337 #if (EMLXS_MODREV >= EMLXS_MODREV3) 338 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL, 339 pkt->pkt_data, real_len, DDI_DMA_READ | DDI_DMA_WRITE | 340 DDI_DMA_CONSISTENT, cb, NULL, pkt->pkt_data_cookie, 341 &pkt->pkt_data_cookie_cnt) != DDI_DMA_MAPPED) 342 #else 343 if (ddi_dma_addr_bind_handle(pkt->pkt_data_dma, NULL, 344 pkt->pkt_data, real_len, DDI_DMA_READ | DDI_DMA_WRITE | 345 DDI_DMA_CONSISTENT, cb, NULL, &pkt->pkt_data_cookie, 346 &num_cookie) != DDI_DMA_MAPPED) 347 #endif /* >= EMLXS_MODREV3 */ 348 { 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 (pkt->pkt_data_cookie_cnt != 1) 357 #else 358 if (num_cookie != 1) 359 #endif /* >= EMLXS_MODREV3 */ 360 { 361 goto failed; 362 } 363 bzero(pkt->pkt_data, datalen); 364 } 365 366 sbp = PKT2PRIV(pkt); 367 bzero((void *)sbp, sizeof (emlxs_buf_t)); 368 369 mutex_init(&sbp->mtx, NULL, MUTEX_DRIVER, (void *)hba->intr_arg); 370 sbp->pkt_flags = PACKET_VALID | PACKET_RETURNED | PACKET_ALLOCATED; 371 sbp->port = port; 372 sbp->pkt = pkt; 373 sbp->iocbq.sbp = sbp; 374 375 return (pkt); 376 377 failed: 378 379 if (datalen) { 380 (void) ddi_dma_unbind_handle(pkt->pkt_data_dma); 381 (void) ddi_dma_mem_free(&pkt->pkt_data_acc); 382 (void) ddi_dma_free_handle(&pkt->pkt_data_dma); 383 } 384 if (rsplen) { 385 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 386 (void) ddi_dma_mem_free(&pkt->pkt_resp_acc); 387 (void) ddi_dma_free_handle(&pkt->pkt_resp_dma); 388 } 389 if (cmdlen) { 390 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 391 (void) ddi_dma_mem_free(&pkt->pkt_cmd_acc); 392 (void) ddi_dma_free_handle(&pkt->pkt_cmd_dma); 393 } 394 if (pkt) { 395 kmem_free(pkt, pkt_size); 396 } 397 return (NULL); 398 399 } /* emlxs_pkt_alloc() */ 400