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