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