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 2017 Joyent, Inc. 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 int 354 av1394_async_poll(av1394_inst_t *avp, short events, int anyyet, short *reventsp, 355 struct pollhead **phpp) 356 { 357 av1394_async_t *ap = &avp->av_a; 358 av1394_queue_t *rq = &ap->a_rq; 359 360 AV1394_TNF_ENTER(av1394_async_poll); 361 362 if (events & (POLLIN | POLLET)) { 363 if ((events & POLLIN) && av1394_peekq(rq)) { 364 *reventsp |= POLLIN; 365 } 366 367 if ((!*reventsp && !anyyet) || (events & POLLET)) { 368 mutex_enter(&ap->a_mutex); 369 if (events & POLLIN) { 370 ap->a_pollevents |= POLLIN; 371 } 372 *phpp = &ap->a_pollhead; 373 mutex_exit(&ap->a_mutex); 374 } 375 } 376 377 AV1394_TNF_EXIT(av1394_async_poll); 378 return (0); 379 } 380 381 382 /* 383 * put a message on the read queue, take care of polling 384 */ 385 void 386 av1394_async_putq_rq(av1394_inst_t *avp, mblk_t *mp) 387 { 388 av1394_async_t *ap = &avp->av_a; 389 390 if (!av1394_putq(&ap->a_rq, mp)) { 391 freemsg(mp); 392 TNF_PROBE_0(av1394_async_putq_rq_error_putq, 393 AV1394_TNF_ASYNC_ERROR, ""); 394 } else { 395 mutex_enter(&ap->a_mutex); 396 if (ap->a_pollevents & POLLIN) { 397 ap->a_pollevents &= ~POLLIN; 398 mutex_exit(&ap->a_mutex); 399 pollwakeup(&ap->a_pollhead, POLLIN); 400 } else { 401 mutex_exit(&ap->a_mutex); 402 } 403 } 404 } 405 406 /* 407 * 408 * --- configuration routines 409 * 410 * av1394_async_cleanup() 411 * Cleanup after attach 412 */ 413 static void 414 av1394_async_cleanup(av1394_inst_t *avp, int level) 415 { 416 av1394_async_t *ap = &avp->av_a; 417 418 ASSERT((level > 0) && (level <= AV1394_CLEANUP_LEVEL_MAX)); 419 420 switch (level) { 421 default: 422 av1394_async_remove_minor_node(avp); 423 /* FALLTHRU */ 424 case 3: 425 av1394_cfgrom_fini(avp); 426 /* FALLTHRU */ 427 case 2: 428 av1394_fcp_detach(avp); 429 /* FALLTHRU */ 430 case 1: 431 av1394_destroyq(&ap->a_rq); 432 mutex_destroy(&ap->a_mutex); 433 } 434 } 435 436 /* 437 * av1394_async_create_minor_node() 438 * Create async minor node 439 */ 440 static int 441 av1394_async_create_minor_node(av1394_inst_t *avp) 442 { 443 int ret; 444 445 ret = ddi_create_minor_node(avp->av_dip, "async", 446 S_IFCHR, AV1394_ASYNC_INST2MINOR(avp->av_instance), 447 DDI_NT_AV_ASYNC, NULL); 448 if (ret != DDI_SUCCESS) { 449 TNF_PROBE_0(av1394_async_create_minor_node_error, 450 AV1394_TNF_ASYNC_ERROR, ""); 451 } 452 return (ret); 453 } 454 455 /* 456 * av1394_async_remove_minor_node() 457 * Remove async minor node 458 */ 459 static void 460 av1394_async_remove_minor_node(av1394_inst_t *avp) 461 { 462 ddi_remove_minor_node(avp->av_dip, "async"); 463 } 464 465 /* 466 * av1394_async_update_targetinfo() 467 * Retrieve target info and bus generation 468 */ 469 static int 470 av1394_async_update_targetinfo(av1394_inst_t *avp) 471 { 472 av1394_async_t *ap = &avp->av_a; 473 uint_t bg; 474 int ret; 475 476 mutex_enter(&avp->av_mutex); 477 bg = avp->av_attachinfo.localinfo.bus_generation; 478 mutex_exit(&avp->av_mutex); 479 480 mutex_enter(&ap->a_mutex); 481 ret = t1394_get_targetinfo(avp->av_t1394_hdl, bg, 0, &ap->a_targetinfo); 482 ap->a_bus_generation = bg; 483 mutex_exit(&ap->a_mutex); 484 485 return (ret); 486 } 487 488 static int 489 av1394_async_db2arq_type(int dbtype) 490 { 491 int arq_type; 492 493 switch (dbtype) { 494 case AV1394_M_FCP_RESP: 495 arq_type = IEC61883_ARQ_FCP_RESP; 496 break; 497 case AV1394_M_FCP_CMD: 498 arq_type = IEC61883_ARQ_FCP_CMD; 499 break; 500 case AV1394_M_BUS_RESET: 501 arq_type = IEC61883_ARQ_BUS_RESET; 502 break; 503 default: 504 ASSERT(0); /* cannot happen */ 505 } 506 return (arq_type); 507 } 508 509 static void 510 av1394_async_putbq(av1394_queue_t *q, mblk_t *mp) 511 { 512 if (!av1394_putbq(q, mp)) { 513 freemsg(mp); 514 TNF_PROBE_0(av1394_async_putbq_error, 515 AV1394_TNF_ASYNC_ERROR, ""); 516 } 517 } 518 519 /*ARGSUSED*/ 520 static int 521 av1394_ioctl_arq_get_ibuf_size(av1394_inst_t *avp, void *arg, int mode) 522 { 523 av1394_async_t *ap = &avp->av_a; 524 int sz; 525 int ret = 0; 526 527 AV1394_TNF_ENTER(av1394_ioctl_arq_get_ibuf_size); 528 529 sz = av1394_getmaxq(&ap->a_rq); 530 531 if (ddi_copyout(&sz, arg, sizeof (sz), mode) != 0) { 532 ret = EFAULT; 533 } 534 535 AV1394_TNF_EXIT(av1394_ioctl_arq_get_ibuf_size); 536 return (ret); 537 } 538 539 /*ARGSUSED*/ 540 static int 541 av1394_ioctl_arq_set_ibuf_size(av1394_inst_t *avp, void *arg, int mode) 542 { 543 av1394_async_t *ap = &avp->av_a; 544 int sz; 545 int ret = 0; 546 547 AV1394_TNF_ENTER(av1394_ioctl_arq_set_ibuf_size); 548 549 sz = (int)(intptr_t)arg; 550 551 if ((sz < 0) || (sz > av1394_ibuf_size_max)) { 552 ret = EINVAL; 553 } else { 554 av1394_setmaxq(&ap->a_rq, sz); 555 } 556 557 AV1394_TNF_EXIT(av1394_ioctl_arq_set_ibuf_size); 558 return (ret); 559 } 560