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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * av1394 asynchronous module 31 */ 32 #include <sys/stat.h> 33 #include <sys/file.h> 34 #include <sys/ddi.h> 35 #include <sys/sunddi.h> 36 #include <sys/1394/targets/av1394/av1394_impl.h> 37 38 /* configuration routines */ 39 static void av1394_async_cleanup(av1394_inst_t *, int); 40 static int av1394_async_create_minor_node(av1394_inst_t *); 41 static void av1394_async_remove_minor_node(av1394_inst_t *); 42 static int av1394_async_update_targetinfo(av1394_inst_t *); 43 static int av1394_async_db2arq_type(int); 44 static void av1394_async_putbq(av1394_queue_t *, mblk_t *); 45 46 static int av1394_ioctl_arq_get_ibuf_size(av1394_inst_t *, void *, int); 47 static int av1394_ioctl_arq_set_ibuf_size(av1394_inst_t *, void *, int); 48 49 #define AV1394_TNF_ENTER(func) \ 50 TNF_PROBE_0_DEBUG(func##_enter, AV1394_TNF_ASYNC_STACK, ""); 51 52 #define AV1394_TNF_EXIT(func) \ 53 TNF_PROBE_0_DEBUG(func##_exit, AV1394_TNF_ASYNC_STACK, ""); 54 55 /* tunables */ 56 int av1394_ibuf_size_default = 64 * 1024; /* default ibuf size */ 57 int av1394_ibuf_size_max = 1024 * 1024; /* max ibuf size */ 58 59 /* 60 * 61 * --- configuration entry points 62 * 63 */ 64 int 65 av1394_async_attach(av1394_inst_t *avp) 66 { 67 av1394_async_t *ap = &avp->av_a; 68 ddi_iblock_cookie_t ibc = avp->av_attachinfo.iblock_cookie; 69 70 AV1394_TNF_ENTER(av1394_async_attach); 71 72 mutex_init(&ap->a_mutex, NULL, MUTEX_DRIVER, ibc); 73 av1394_initq(&ap->a_rq, ibc, av1394_ibuf_size_default); 74 75 if (av1394_fcp_attach(avp) != DDI_SUCCESS) { 76 av1394_async_cleanup(avp, 1); 77 AV1394_TNF_EXIT(av1394_async_attach); 78 return (DDI_FAILURE); 79 } 80 81 if (av1394_cfgrom_init(avp) != DDI_SUCCESS) { 82 av1394_async_cleanup(avp, 2); 83 AV1394_TNF_EXIT(av1394_async_attach); 84 return (DDI_FAILURE); 85 } 86 87 if (av1394_async_create_minor_node(avp) != DDI_SUCCESS) { 88 av1394_async_cleanup(avp, 3); 89 AV1394_TNF_EXIT(av1394_async_attach); 90 return (DDI_FAILURE); 91 } 92 93 if (av1394_async_update_targetinfo(avp) != DDI_SUCCESS) { 94 av1394_async_cleanup(avp, 4); 95 AV1394_TNF_EXIT(av1394_async_attach); 96 return (DDI_FAILURE); 97 } 98 99 AV1394_TNF_EXIT(av1394_async_attach); 100 return (DDI_SUCCESS); 101 } 102 103 void 104 av1394_async_detach(av1394_inst_t *avp) 105 { 106 AV1394_TNF_ENTER(av1394_async_detach); 107 108 av1394_async_cleanup(avp, AV1394_CLEANUP_LEVEL_MAX); 109 110 AV1394_TNF_EXIT(av1394_async_detach); 111 } 112 113 void 114 av1394_async_bus_reset(av1394_inst_t *avp) 115 { 116 av1394_async_t *ap = &avp->av_a; 117 mblk_t *bp; 118 119 AV1394_TNF_ENTER(av1394_async_bus_reset); 120 121 (void) av1394_async_update_targetinfo(avp); 122 123 mutex_enter(&ap->a_mutex); 124 if (ap->a_nopen > 0) { 125 mutex_exit(&ap->a_mutex); 126 return; 127 } 128 mutex_exit(&ap->a_mutex); 129 130 /* queue up a bus reset message */ 131 if ((bp = allocb(1, BPRI_HI)) == NULL) { 132 TNF_PROBE_0(av1394_async_bus_reset_error_allocb, 133 AV1394_TNF_ASYNC_ERROR, ""); 134 } else { 135 DB_TYPE(bp) = AV1394_M_BUS_RESET; 136 av1394_async_putq_rq(avp, bp); 137 } 138 139 AV1394_TNF_EXIT(av1394_async_bus_reset); 140 } 141 142 int 143 av1394_async_cpr_resume(av1394_inst_t *avp) 144 { 145 int ret; 146 147 AV1394_TNF_ENTER(av1394_async_cpr_resume); 148 149 ret = av1394_async_update_targetinfo(avp); 150 151 AV1394_TNF_EXIT(av1394_async_cpr_resume); 152 return (ret); 153 } 154 155 void 156 av1394_async_reconnect(av1394_inst_t *avp) 157 { 158 AV1394_TNF_ENTER(av1394_async_reconnect); 159 160 (void) av1394_async_update_targetinfo(avp); 161 162 AV1394_TNF_EXIT(av1394_async_reconnect); 163 } 164 165 int 166 av1394_async_open(av1394_inst_t *avp, int flag) 167 { 168 av1394_async_t *ap = &avp->av_a; 169 170 AV1394_TNF_ENTER(av1394_async_open); 171 172 mutex_enter(&ap->a_mutex); 173 if (ap->a_nopen == 0) { 174 ap->a_pollevents = 0; 175 } 176 ap->a_nopen++; 177 ap->a_oflag = flag; 178 mutex_exit(&ap->a_mutex); 179 180 AV1394_TNF_EXIT(av1394_async_open); 181 return (0); 182 } 183 184 /*ARGSUSED*/ 185 int 186 av1394_async_close(av1394_inst_t *avp, int flag) 187 { 188 av1394_async_t *ap = &avp->av_a; 189 190 AV1394_TNF_ENTER(av1394_async_close); 191 192 av1394_cfgrom_close(avp); 193 194 av1394_flushq(&ap->a_rq); 195 196 mutex_enter(&ap->a_mutex); 197 ap->a_nopen = 0; 198 ap->a_pollevents = 0; 199 mutex_exit(&ap->a_mutex); 200 201 AV1394_TNF_EXIT(av1394_async_close); 202 return (0); 203 } 204 205 int 206 av1394_async_read(av1394_inst_t *avp, struct uio *uiop) 207 { 208 av1394_async_t *ap = &avp->av_a; 209 av1394_queue_t *q = &ap->a_rq; 210 iec61883_arq_t arq; 211 int ret = 0; 212 mblk_t *mp; 213 int dbtype; 214 int len; 215 216 AV1394_TNF_ENTER(av1394_async_read); 217 218 /* copyout as much as we can */ 219 while ((uiop->uio_resid > 0) && (ret == 0)) { 220 /* 221 * if data is available, copy it out. otherwise wait until 222 * data arrives, unless opened with non-blocking flag 223 */ 224 if ((mp = av1394_getq(q)) == NULL) { 225 if (ap->a_oflag & FNDELAY) { 226 AV1394_TNF_EXIT(av1394_async_read); 227 return (EAGAIN); 228 } 229 if (av1394_qwait_sig(q) <= 0) { 230 ret = EINTR; 231 } 232 continue; 233 } 234 dbtype = AV1394_DBTYPE(mp); 235 236 /* generate and copyout ARQ header, if not already */ 237 if (!AV1394_IS_NOHDR(mp)) { 238 /* headers cannot be partially read */ 239 if (uiop->uio_resid < sizeof (arq)) { 240 av1394_async_putbq(q, mp); 241 ret = EINVAL; 242 break; 243 } 244 245 arq.arq_type = av1394_async_db2arq_type(dbtype); 246 arq.arq_len = MBLKL(mp); 247 arq.arq_data.octlet = 0; 248 249 /* copy ARQ-embedded data */ 250 len = min(arq.arq_len, sizeof (arq.arq_data)); 251 bcopy(mp->b_rptr, &arq.arq_data.buf[0], len); 252 253 /* copyout the ARQ */ 254 ret = uiomove(&arq, sizeof (arq), UIO_READ, uiop); 255 if (ret != 0) { 256 av1394_async_putbq(q, mp); 257 break; 258 } 259 mp->b_rptr += len; 260 AV1394_MARK_NOHDR(mp); 261 } 262 263 /* any data left? */ 264 if (MBLKL(mp) == 0) { 265 freemsg(mp); 266 continue; 267 } 268 269 /* now we have some data and some user buffer space to fill */ 270 len = min(uiop->uio_resid, MBLKL(mp)); 271 if (len > 0) { 272 ret = uiomove(mp->b_rptr, len, UIO_READ, uiop); 273 if (ret != 0) { 274 av1394_async_putbq(q, mp); 275 break; 276 } 277 mp->b_rptr += len; 278 } 279 280 /* save the rest of the data for later */ 281 if (MBLKL(mp) > 0) { 282 av1394_async_putbq(q, mp); 283 } 284 } 285 286 AV1394_TNF_EXIT(av1394_async_read); 287 return (0); 288 } 289 290 int 291 av1394_async_write(av1394_inst_t *avp, struct uio *uiop) 292 { 293 iec61883_arq_t arq; 294 int ret; 295 296 AV1394_TNF_ENTER(av1394_async_write); 297 298 /* all data should arrive in ARQ format */ 299 while (uiop->uio_resid >= sizeof (arq)) { 300 if ((ret = uiomove(&arq, sizeof (arq), UIO_WRITE, uiop)) != 0) { 301 break; 302 } 303 304 switch (arq.arq_type) { 305 case IEC61883_ARQ_FCP_CMD: 306 case IEC61883_ARQ_FCP_RESP: 307 ret = av1394_fcp_write(avp, &arq, uiop); 308 break; 309 default: 310 ret = EINVAL; 311 } 312 if (ret != 0) { 313 break; 314 } 315 } 316 317 AV1394_TNF_EXIT(av1394_async_write); 318 return (ret); 319 } 320 321 /*ARGSUSED*/ 322 int 323 av1394_async_ioctl(av1394_inst_t *avp, int cmd, intptr_t arg, int mode, 324 int *rvalp) 325 { 326 int ret = EINVAL; 327 328 AV1394_TNF_ENTER(av1394_async_ioctl); 329 330 switch (cmd) { 331 case IEC61883_ARQ_GET_IBUF_SIZE: 332 ret = av1394_ioctl_arq_get_ibuf_size(avp, (void *)arg, mode); 333 break; 334 case IEC61883_ARQ_SET_IBUF_SIZE: 335 ret = av1394_ioctl_arq_set_ibuf_size(avp, (void *)arg, mode); 336 break; 337 case IEC61883_NODE_GET_BUS_NAME: 338 ret = av1394_ioctl_node_get_bus_name(avp, (void *)arg, mode); 339 break; 340 case IEC61883_NODE_GET_UID: 341 ret = av1394_ioctl_node_get_uid(avp, (void *)arg, mode); 342 break; 343 case IEC61883_NODE_GET_TEXT_LEAF: 344 ret = av1394_ioctl_node_get_text_leaf(avp, (void *)arg, mode); 345 } 346 347 AV1394_TNF_EXIT(av1394_async_ioctl); 348 return (ret); 349 } 350 351 /*ARGSUSED*/ 352 int 353 av1394_async_poll(av1394_inst_t *avp, short events, int anyyet, short *reventsp, 354 struct pollhead **phpp) 355 { 356 av1394_async_t *ap = &avp->av_a; 357 av1394_queue_t *rq = &ap->a_rq; 358 359 AV1394_TNF_ENTER(av1394_async_poll); 360 361 if (events & POLLIN) { 362 if (av1394_peekq(rq)) { 363 *reventsp |= POLLIN; 364 } else if (!anyyet) { 365 mutex_enter(&ap->a_mutex); 366 ap->a_pollevents |= POLLIN; 367 *phpp = &ap->a_pollhead; 368 mutex_exit(&ap->a_mutex); 369 } 370 } 371 372 AV1394_TNF_EXIT(av1394_async_poll); 373 return (0); 374 } 375 376 377 /* 378 * put a message on the read queue, take care of polling 379 */ 380 void 381 av1394_async_putq_rq(av1394_inst_t *avp, mblk_t *mp) 382 { 383 av1394_async_t *ap = &avp->av_a; 384 385 if (!av1394_putq(&ap->a_rq, mp)) { 386 freemsg(mp); 387 TNF_PROBE_0(av1394_async_putq_rq_error_putq, 388 AV1394_TNF_ASYNC_ERROR, ""); 389 } else { 390 mutex_enter(&ap->a_mutex); 391 if (ap->a_pollevents & POLLIN) { 392 ap->a_pollevents &= ~POLLIN; 393 mutex_exit(&ap->a_mutex); 394 pollwakeup(&ap->a_pollhead, POLLIN); 395 } else { 396 mutex_exit(&ap->a_mutex); 397 } 398 } 399 } 400 401 /* 402 * 403 * --- configuration routines 404 * 405 * av1394_async_cleanup() 406 * Cleanup after attach 407 */ 408 static void 409 av1394_async_cleanup(av1394_inst_t *avp, int level) 410 { 411 av1394_async_t *ap = &avp->av_a; 412 413 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX)); 414 415 switch (level) { 416 default: 417 av1394_async_remove_minor_node(avp); 418 /* FALLTHRU */ 419 case 3: 420 av1394_cfgrom_fini(avp); 421 /* FALLTHRU */ 422 case 2: 423 av1394_fcp_detach(avp); 424 /* FALLTHRU */ 425 case 1: 426 av1394_destroyq(&ap->a_rq); 427 mutex_destroy(&ap->a_mutex); 428 } 429 } 430 431 /* 432 * av1394_async_create_minor_node() 433 * Create async minor node 434 */ 435 static int 436 av1394_async_create_minor_node(av1394_inst_t *avp) 437 { 438 int ret; 439 440 ret = ddi_create_minor_node(avp->av_dip, "async", 441 S_IFCHR, AV1394_ASYNC_INST2MINOR(avp->av_instance), 442 DDI_NT_AV_ASYNC, NULL); 443 if (ret != DDI_SUCCESS) { 444 TNF_PROBE_0(av1394_async_create_minor_node_error, 445 AV1394_TNF_ASYNC_ERROR, ""); 446 } 447 return (ret); 448 } 449 450 /* 451 * av1394_async_remove_minor_node() 452 * Remove async minor node 453 */ 454 static void 455 av1394_async_remove_minor_node(av1394_inst_t *avp) 456 { 457 ddi_remove_minor_node(avp->av_dip, "async"); 458 } 459 460 /* 461 * av1394_async_update_targetinfo() 462 * Retrieve target info and bus generation 463 */ 464 static int 465 av1394_async_update_targetinfo(av1394_inst_t *avp) 466 { 467 av1394_async_t *ap = &avp->av_a; 468 uint_t bg; 469 int ret; 470 471 mutex_enter(&avp->av_mutex); 472 bg = avp->av_attachinfo.localinfo.bus_generation; 473 mutex_exit(&avp->av_mutex); 474 475 mutex_enter(&ap->a_mutex); 476 ret = t1394_get_targetinfo(avp->av_t1394_hdl, bg, 0, &ap->a_targetinfo); 477 ap->a_bus_generation = bg; 478 mutex_exit(&ap->a_mutex); 479 480 return (ret); 481 } 482 483 static int 484 av1394_async_db2arq_type(int dbtype) 485 { 486 int arq_type; 487 488 switch (dbtype) { 489 case AV1394_M_FCP_RESP: 490 arq_type = IEC61883_ARQ_FCP_RESP; 491 break; 492 case AV1394_M_FCP_CMD: 493 arq_type = IEC61883_ARQ_FCP_CMD; 494 break; 495 case AV1394_M_BUS_RESET: 496 arq_type = IEC61883_ARQ_BUS_RESET; 497 break; 498 default: 499 ASSERT(0); /* cannot happen */ 500 } 501 return (arq_type); 502 } 503 504 static void 505 av1394_async_putbq(av1394_queue_t *q, mblk_t *mp) 506 { 507 if (!av1394_putbq(q, mp)) { 508 freemsg(mp); 509 TNF_PROBE_0(av1394_async_putbq_error, 510 AV1394_TNF_ASYNC_ERROR, ""); 511 } 512 } 513 514 /*ARGSUSED*/ 515 static int 516 av1394_ioctl_arq_get_ibuf_size(av1394_inst_t *avp, void *arg, int mode) 517 { 518 av1394_async_t *ap = &avp->av_a; 519 int sz; 520 int ret = 0; 521 522 AV1394_TNF_ENTER(av1394_ioctl_arq_get_ibuf_size); 523 524 sz = av1394_getmaxq(&ap->a_rq); 525 526 if (ddi_copyout(&sz, arg, sizeof (sz), mode) != 0) { 527 ret = EFAULT; 528 } 529 530 AV1394_TNF_EXIT(av1394_ioctl_arq_get_ibuf_size); 531 return (ret); 532 } 533 534 /*ARGSUSED*/ 535 static int 536 av1394_ioctl_arq_set_ibuf_size(av1394_inst_t *avp, void *arg, int mode) 537 { 538 av1394_async_t *ap = &avp->av_a; 539 int sz; 540 int ret = 0; 541 542 AV1394_TNF_ENTER(av1394_ioctl_arq_set_ibuf_size); 543 544 sz = (int)(intptr_t)arg; 545 546 if ((sz < 0) || (sz > av1394_ibuf_size_max)) { 547 ret = EINVAL; 548 } else { 549 av1394_setmaxq(&ap->a_rq, sz); 550 } 551 552 AV1394_TNF_EXIT(av1394_ioctl_arq_set_ibuf_size); 553 return (ret); 554 } 555