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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26
27 /*
28 * DM2S - Domain side Mailbox to synchronous serial device driver.
29 *
30 * Description:
31 * -----------
32 * It is a streams driver which simulates a sync serial device on
33 * top of a mailbox type of communication. That is, it sends/receives
34 * frames as mailbox messages. The mailbox communication is provided
35 * by another driver, which exports the mailbox interfaces.
36 *
37 * Synchronization:
38 * ---------------
39 * This driver uses streams perimeters to simplify the synchronization.
40 * An inner perimeter D_MTPERMOD which protects the entire module,
41 * that is only one thread exists inside the perimeter, is used. As
42 * this driver supports only one instance and is not a high-performance
43 * driver, D_MTPERMOD is highly suitable.
44 *
45 * All transmission and reception of frames is done inside the service
46 * procedures so that all streams related operations are protected
47 * by the perimeters.
48 *
49 * The mailbox event handler is the only asynchronous callback which
50 * needs to be protected outside of the streams perimeters. This is
51 * done using the module private lock('ms_lock');
52 *
53 */
54
55 #include <sys/types.h>
56 #include <sys/param.h>
57 #include <sys/stream.h>
58 #include <sys/cred.h>
59 #include <sys/systm.h>
60 #include <sys/sunddi.h>
61 #include <sys/ddi.h>
62 #include <sys/conf.h>
63 #include <sys/modctl.h>
64 #include <sys/mkdev.h>
65 #include <sys/errno.h>
66 #include <sys/debug.h>
67 #include <sys/kbio.h>
68 #include <sys/kmem.h>
69 #include <sys/consdev.h>
70 #include <sys/file.h>
71 #include <sys/stropts.h>
72 #include <sys/strsun.h>
73 #include <sys/dlpi.h>
74 #include <sys/stat.h>
75 #include <sys/ser_sync.h>
76 #include <sys/sysmacros.h>
77 #include <sys/note.h>
78 #include <sys/sdt.h>
79
80 #include <sys/scfd/scfdscpif.h>
81 #include <sys/dm2s.h>
82
83
84 #define DM2S_MODNAME "dm2s" /* Module name */
85 #define DM2S_TARGET_ID 0 /* Target ID of the peer */
86 #define DM2S_ID_NUM 0x4D53 /* 'M''S' */
87 #define DM2S_DEF_MTU 1504 /* Def. MTU size + PPP bytes */
88 #define DM2S_MAXPSZ DM2S_DEF_MTU /* Set it to the default MTU */
89 #define DM2S_LOWAT (4 * 1024) /* Low water mark */
90 #define DM2S_HIWAT (12 * 1024) /* High water mark */
91 #define DM2S_SM_TOUT 5000 /* Small timeout (5msec) */
92 #define DM2S_LG_TOUT 50000 /* Large timeout (50msec) */
93 #define DM2S_MB_TOUT 10000000 /* Mailbox timeout (10sec) */
94
95 /*
96 * Global variables
97 */
98 void *dm2s_softstate = NULL; /* Softstate pointer */
99
100
101 /*
102 * Prototypes for the module related functions.
103 */
104 int dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
105 int dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
106 int dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd,
107 void *arg, void **result);
108
109 /*
110 * Prototypes for the streams related functions.
111 */
112 int dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr);
113 int dm2s_close(queue_t *rq, int flag, cred_t *cred);
114 int dm2s_wput(queue_t *wq, mblk_t *mp);
115 int dm2s_rsrv(queue_t *rq);
116 int dm2s_wsrv(queue_t *wq);
117
118 /*
119 * Prototypes for the internal functions.
120 */
121 void dm2s_start(queue_t *wq, dm2s_t *dm2sp);
122 void dm2s_event_handler(scf_event_t event, void *arg);
123 int dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key);
124 void dm2s_receive(dm2s_t *dm2sp);
125 void dm2s_wq_timeout(void *arg);
126 void dm2s_rq_timeout(void *arg);
127 void dm2s_bufcall_rcv(void *arg);
128 static clock_t dm2s_timeout_val(int error);
129 static void dm2s_cleanup(dm2s_t *dm2sp);
130 static int dm2s_mbox_init(dm2s_t *dm2sp);
131 static void dm2s_mbox_fini(dm2s_t *dm2sp);
132 static int dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg,
133 mscat_gath_t *sgp, int maxsg);
134
135 #ifdef DEBUG
136 uint32_t dm2s_debug = DBG_WARN;
137 #endif /* DEBUG */
138
139
140 /*
141 * Streams and module related structures.
142 */
143 struct module_info dm2s_module_info = {
144 DM2S_ID_NUM, /* module ID number */
145 DM2S_MODNAME, /* module name. */
146 0, /* Minimum packet size (none) */
147 DM2S_MAXPSZ, /* Maximum packet size (none) */
148 DM2S_HIWAT, /* queue high water mark */
149 DM2S_LOWAT /* queue low water mark */
150 };
151
152 struct qinit dm2s_rinit = {
153 putq, /* qi_putp */
154 dm2s_rsrv, /* qi_srvp */
155 dm2s_open, /* qi_qopen */
156 dm2s_close, /* qi_qlcose */
157 NULL, /* qi_qadmin */
158 &dm2s_module_info, /* qi_minfo */
159 NULL /* qi_mstat */
160 };
161
162 struct qinit dm2s_winit = {
163 dm2s_wput, /* qi_putp */
164 dm2s_wsrv, /* qi_srvp */
165 NULL, /* qi_qopen */
166 NULL, /* qi_qlcose */
167 NULL, /* qi_qadmin */
168 &dm2s_module_info, /* qi_minfo */
169 NULL /* qi_mstat */
170 };
171
172
173 struct streamtab dm2s_streamtab = {
174 &dm2s_rinit,
175 &dm2s_winit,
176 NULL,
177 NULL
178 };
179
180 DDI_DEFINE_STREAM_OPS(dm2s_ops, nulldev, nulldev, dm2s_attach,
181 dm2s_detach, nodev, dm2s_info, D_NEW | D_MP | D_MTPERMOD,
182 &dm2s_streamtab, ddi_quiesce_not_supported);
183
184
185 struct modldrv modldrv = {
186 &mod_driverops,
187 "OPL Mbox to Serial Driver",
188 &dm2s_ops
189 };
190
191 struct modlinkage modlinkage = {
192 MODREV_1,
193 &modldrv,
194 NULL
195 };
196
197
198 /*
199 * _init - Module's init routine.
200 */
201 int
_init(void)202 _init(void)
203 {
204 int ret;
205
206 if (ddi_soft_state_init(&dm2s_softstate, sizeof (dm2s_t), 1) != 0) {
207 cmn_err(CE_WARN, "softstate initialization failed\n");
208 return (DDI_FAILURE);
209 }
210 if ((ret = mod_install(&modlinkage)) != 0) {
211 cmn_err(CE_WARN, "mod_install failed, error = %d", ret);
212 ddi_soft_state_fini(&dm2s_softstate);
213 }
214 return (ret);
215 }
216
217 /*
218 * _fini - Module's fini routine.
219 */
220 int
_fini(void)221 _fini(void)
222 {
223 int ret;
224
225 if ((ret = mod_remove(&modlinkage)) != 0) {
226 return (ret);
227 }
228 ddi_soft_state_fini(&dm2s_softstate);
229 return (ret);
230 }
231
232 /*
233 * _info - Module's info routine.
234 */
235 int
_info(struct modinfo * modinfop)236 _info(struct modinfo *modinfop)
237 {
238 return (mod_info(&modlinkage, modinfop));
239 }
240
241 /*
242 * dm2s_attach - Module's attach routine.
243 */
244 int
dm2s_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)245 dm2s_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
246 {
247 int instance;
248 dm2s_t *dm2sp;
249 char name[20];
250
251
252 instance = ddi_get_instance(dip);
253
254 /* Only one instance is supported. */
255 if (instance != 0) {
256 cmn_err(CE_WARN, "only one instance is supported");
257 return (DDI_FAILURE);
258 }
259
260 if (cmd != DDI_ATTACH) {
261 return (DDI_FAILURE);
262 }
263 if (ddi_soft_state_zalloc(dm2s_softstate, instance) != DDI_SUCCESS) {
264 cmn_err(CE_WARN, "softstate allocation failure");
265 return (DDI_FAILURE);
266 }
267 dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance);
268 if (dm2sp == NULL) {
269 ddi_soft_state_free(dm2s_softstate, instance);
270 cmn_err(CE_WARN, "softstate allocation failure.");
271 return (DDI_FAILURE);
272 }
273 dm2sp->ms_dip = dip;
274 dm2sp->ms_major = ddi_driver_major(dip);
275 dm2sp->ms_ppa = instance;
276
277 /*
278 * Get an interrupt block cookie corresponding to the
279 * interrupt priority of the event handler.
280 * Assert that the event priority is not re-defined to
281 * some higher priority.
282 */
283 /* LINTED */
284 ASSERT(SCF_EVENT_PRI == DDI_SOFTINT_LOW);
285 if (ddi_get_soft_iblock_cookie(dip, SCF_EVENT_PRI,
286 &dm2sp->ms_ibcookie) != DDI_SUCCESS) {
287 cmn_err(CE_WARN, "ddi_get_soft_iblock_cookie failed.");
288 goto error;
289 }
290 mutex_init(&dm2sp->ms_lock, NULL, MUTEX_DRIVER,
291 (void *)dm2sp->ms_ibcookie);
292
293 dm2sp->ms_clean |= DM2S_CLEAN_LOCK;
294 cv_init(&dm2sp->ms_wait, NULL, CV_DRIVER, NULL);
295 dm2sp->ms_clean |= DM2S_CLEAN_CV;
296
297 (void) sprintf(name, "%s%d", DM2S_MODNAME, instance);
298 if (ddi_create_minor_node(dip, name, S_IFCHR, instance,
299 DDI_PSEUDO, 0) == DDI_FAILURE) {
300 ddi_remove_minor_node(dip, NULL);
301 cmn_err(CE_WARN, "Device node creation failed.");
302 goto error;
303 }
304
305 dm2sp->ms_clean |= DM2S_CLEAN_NODE;
306 ddi_set_driver_private(dip, (caddr_t)dm2sp);
307 ddi_report_dev(dip);
308 return (DDI_SUCCESS);
309 error:
310 dm2s_cleanup(dm2sp);
311 return (DDI_FAILURE);
312 }
313
314 /*
315 * dm2s_info - Module's info routine.
316 */
317 /*ARGSUSED*/
318 int
dm2s_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)319 dm2s_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
320 {
321 dm2s_t *dm2sp;
322 minor_t minor;
323 int ret = DDI_FAILURE;
324
325 switch (infocmd) {
326 case DDI_INFO_DEVT2DEVINFO:
327 minor = getminor((dev_t)arg);
328 dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, minor);
329 if (dm2sp == NULL) {
330 *result = NULL;
331 } else {
332 *result = dm2sp->ms_dip;
333 ret = DDI_SUCCESS;
334 }
335 break;
336
337 case DDI_INFO_DEVT2INSTANCE:
338 minor = getminor((dev_t)arg);
339 *result = (void *)(uintptr_t)minor;
340 ret = DDI_SUCCESS;
341 break;
342
343 default:
344 break;
345 }
346 return (ret);
347 }
348
349 /*
350 * dm2s_detach - Module's detach routine.
351 */
352 int
dm2s_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)353 dm2s_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
354 {
355 int instance;
356 dm2s_t *dm2sp;
357
358 if (cmd != DDI_DETACH) {
359 return (DDI_FAILURE);
360 }
361
362 instance = ddi_get_instance(dip);
363 dm2sp = (dm2s_t *)ddi_get_soft_state(dm2s_softstate, instance);
364 if (dm2sp == NULL) {
365 return (DDI_FAILURE);
366 }
367
368 mutex_enter(&dm2sp->ms_lock);
369
370 /* Check if the mailbox is still in use. */
371 if (dm2sp->ms_state & DM2S_MB_INITED) {
372 mutex_exit(&dm2sp->ms_lock);
373 cmn_err(CE_WARN, "Mailbox in use: Detach failed");
374 return (DDI_FAILURE);
375 }
376 mutex_exit(&dm2sp->ms_lock);
377 dm2s_cleanup(dm2sp);
378 return (DDI_SUCCESS);
379 }
380
381 /*
382 * dm2s_open - Device open routine.
383 *
384 * Only one open supported. Clone open is not supported.
385 */
386 /* ARGSUSED */
387 int
dm2s_open(queue_t * rq,dev_t * dev,int flag,int sflag,cred_t * cr)388 dm2s_open(queue_t *rq, dev_t *dev, int flag, int sflag, cred_t *cr)
389 {
390 dm2s_t *dm2sp;
391 int instance = getminor(*dev);
392 int ret = 0;
393
394 DPRINTF(DBG_DRV, ("dm2s_open: called\n"));
395 if (sflag == CLONEOPEN) {
396 /* Clone open not supported */
397 DPRINTF(DBG_WARN, ("dm2s_open: clone open not supported\n"));
398 return (ENOTSUP);
399 }
400
401 if (rq->q_ptr != NULL) {
402 DPRINTF(DBG_WARN, ("dm2s_open: already opened\n"));
403 return (EBUSY);
404 }
405
406 if ((dm2sp = ddi_get_soft_state(dm2s_softstate, instance)) == NULL) {
407 DPRINTF(DBG_WARN, ("dm2s_open: instance not found\n"));
408 return (ENODEV);
409 }
410
411 mutex_enter(&dm2sp->ms_lock);
412 if (dm2sp->ms_state & DM2S_OPENED) {
413 /* Only one open supported */
414 mutex_exit(&dm2sp->ms_lock);
415 DPRINTF(DBG_WARN, ("dm2s_open: already opened\n"));
416 return (EBUSY);
417 }
418
419 dm2sp->ms_state |= DM2S_OPENED;
420 /* Initialize the mailbox. */
421 if ((ret = dm2s_mbox_init(dm2sp)) != 0) {
422 dm2sp->ms_state = 0;
423 mutex_exit(&dm2sp->ms_lock);
424 return (ret);
425 }
426 rq->q_ptr = WR(rq)->q_ptr = (void *)dm2sp;
427 dm2sp->ms_rq = rq;
428 dm2sp->ms_wq = WR(rq);
429 mutex_exit(&dm2sp->ms_lock);
430
431 if (ret == 0) {
432 qprocson(rq); /* now schedule our queue */
433 }
434 DPRINTF(DBG_DRV, ("dm2s_open: ret=%d\n", ret));
435 return (ret);
436 }
437
438 /*
439 * dm2s_close - Device close routine.
440 */
441 /* ARGSUSED */
442 int
dm2s_close(queue_t * rq,int flag,cred_t * cred)443 dm2s_close(queue_t *rq, int flag, cred_t *cred)
444 {
445 dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;
446
447 DPRINTF(DBG_DRV, ("dm2s_close: called\n"));
448 if (dm2sp == NULL) {
449 /* Already closed once */
450 return (ENODEV);
451 }
452
453 /* Close the lower layer first */
454 mutex_enter(&dm2sp->ms_lock);
455 (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL);
456 dm2s_mbox_fini(dm2sp);
457 mutex_exit(&dm2sp->ms_lock);
458
459 /*
460 * Now we can assume that no asynchronous callbacks exist.
461 * Poison the stream head so that we can't be pushed again.
462 */
463 (void) putnextctl(rq, M_HANGUP);
464 qprocsoff(rq);
465 if (dm2sp->ms_rbufcid != 0) {
466 qunbufcall(rq, dm2sp->ms_rbufcid);
467 dm2sp->ms_rbufcid = 0;
468 }
469 if (dm2sp->ms_rq_timeoutid != 0) {
470 DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp);
471 (void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid);
472 dm2sp->ms_rq_timeoutid = 0;
473 }
474 if (dm2sp->ms_wq_timeoutid != 0) {
475 DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp);
476 (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid);
477 dm2sp->ms_wq_timeoutid = 0;
478 }
479 /*
480 * Now we can really mark it closed.
481 */
482 mutex_enter(&dm2sp->ms_lock);
483 dm2sp->ms_rq = dm2sp->ms_wq = NULL;
484 dm2sp->ms_state &= ~DM2S_OPENED;
485 mutex_exit(&dm2sp->ms_lock);
486
487 rq->q_ptr = WR(rq)->q_ptr = NULL;
488 (void) qassociate(rq, -1);
489 DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n"));
490 return (0);
491 }
492
493 /*
494 * dm2s_rsrv - Streams read side service procedure.
495 *
496 * All messages are received in the service procedure
497 * only. This is done to simplify the streams synchronization.
498 */
499 int
dm2s_rsrv(queue_t * rq)500 dm2s_rsrv(queue_t *rq)
501 {
502 mblk_t *mp;
503 dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr;
504
505 DPRINTF(DBG_DRV, ("dm2s_rsrv: called\n"));
506 ASSERT(dm2sp != NULL);
507 mutex_enter(&dm2sp->ms_lock);
508
509 /* Receive if there are any messages waiting in the mailbox. */
510 dm2s_receive(dm2sp);
511 mutex_exit(&dm2sp->ms_lock);
512
513 /* Send the received messages up the stream. */
514 while ((mp = getq(rq)) != NULL) {
515 if (canputnext(rq)) {
516 putnext(rq, mp);
517 } else {
518 (void) putbq(rq, mp);
519 break;
520 }
521 }
522 DPRINTF(DBG_DRV, ("dm2s_rsrv: return\n"));
523 return (0);
524 }
525
526 /*
527 * dm2s_wsrv - Streams write side service procedure.
528 *
529 * All messages are transmitted in the service procedure
530 * only. This is done to simplify the streams synchronization.
531 */
532 int
dm2s_wsrv(queue_t * wq)533 dm2s_wsrv(queue_t *wq)
534 {
535 dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
536
537 DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n"));
538 ASSERT(dm2sp != NULL);
539 /* Lets cancel any timeouts waiting to be scheduled. */
540 if (dm2sp->ms_wq_timeoutid != 0) {
541 DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp);
542 (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid);
543 dm2sp->ms_wq_timeoutid = 0;
544 }
545 mutex_enter(&dm2sp->ms_lock);
546 dm2s_start(wq, dm2sp);
547 mutex_exit(&dm2sp->ms_lock);
548 DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n"));
549 return (0);
550 }
551
552 /*
553 * dm2s_wput - Streams write side put routine.
554 *
555 * All M_DATA messages are queued so that they are transmitted in
556 * the service procedure. This is done to simplify the streams
557 * synchronization. Other messages are handled appropriately.
558 */
559 int
dm2s_wput(queue_t * wq,mblk_t * mp)560 dm2s_wput(queue_t *wq, mblk_t *mp)
561 {
562 dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
563
564 DPRINTF(DBG_DRV, ("dm2s_wput: called\n"));
565 if (dm2sp == NULL) {
566 return (ENODEV); /* Can't happen. */
567 }
568
569 switch (mp->b_datap->db_type) {
570 case (M_DATA):
571 DPRINTF(DBG_DRV, ("dm2s_wput: M_DATA message\n"));
572 while (mp->b_wptr == mp->b_rptr) {
573 mblk_t *mp1;
574
575 mp1 = unlinkb(mp);
576 freemsg(mp);
577 mp = mp1;
578 if (mp == NULL) {
579 return (0);
580 }
581 }
582
583 /*
584 * Simply queue the message and handle it in the service
585 * procedure.
586 */
587 (void) putq(wq, mp);
588 qenable(wq);
589 return (0);
590
591 case (M_PROTO):
592 DPRINTF(DBG_DRV, ("dm2s_wput: M_PROTO message\n"));
593 /* We don't expect this */
594 mp->b_datap->db_type = M_ERROR;
595 mp->b_rptr = mp->b_wptr = mp->b_datap->db_base;
596 *mp->b_wptr++ = EPROTO;
597 qreply(wq, mp);
598 return (EINVAL);
599
600 case (M_IOCTL):
601 DPRINTF(DBG_DRV, ("dm2s_wput: M_IOCTL message\n"));
602 if (MBLKL(mp) < sizeof (struct iocblk)) {
603 freemsg(mp);
604 return (0);
605 }
606 /*
607 * No ioctls required to be supported by this driver, so
608 * return EINVAL for all ioctls.
609 */
610 miocnak(wq, mp, 0, EINVAL);
611 break;
612
613 case (M_CTL):
614 DPRINTF(DBG_DRV, ("dm2s_wput: M_CTL message\n"));
615 /*
616 * No M_CTL messages need to supported by this driver,
617 * so simply ignore them.
618 */
619 freemsg(mp);
620 break;
621
622 case (M_FLUSH):
623 DPRINTF(DBG_DRV, (
624 "dm2s_wput: M_FLUSH message 0x%X\n", *mp->b_rptr));
625 if (*mp->b_rptr & FLUSHW) { /* Flush write-side */
626 (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
627 MB_FLUSH_SEND);
628 flushq(wq, FLUSHDATA);
629 *mp->b_rptr &= ~FLUSHW;
630 }
631 if (*mp->b_rptr & FLUSHR) {
632 (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key,
633 MB_FLUSH_RECEIVE);
634 flushq(RD(wq), FLUSHDATA);
635 qreply(wq, mp);
636 } else {
637 freemsg(mp);
638 }
639 break;
640
641 default:
642 DPRINTF(DBG_DRV, ("dm2s_wput: UNKNOWN message\n"));
643 freemsg(mp);
644
645 }
646 return (0);
647 }
648
649 /*
650 * dm2s_cleanup - Cleanup routine.
651 */
652 static void
dm2s_cleanup(dm2s_t * dm2sp)653 dm2s_cleanup(dm2s_t *dm2sp)
654 {
655 char name[20];
656
657 DPRINTF(DBG_DRV, ("dm2s_cleanup: called\n"));
658 ASSERT(dm2sp != NULL);
659 if (dm2sp->ms_clean & DM2S_CLEAN_NODE) {
660 (void) sprintf(name, "%s%d", DM2S_MODNAME, dm2sp->ms_ppa);
661 ddi_remove_minor_node(dm2sp->ms_dip, name);
662 }
663 if (dm2sp->ms_clean & DM2S_CLEAN_LOCK)
664 mutex_destroy(&dm2sp->ms_lock);
665 if (dm2sp->ms_clean & DM2S_CLEAN_CV)
666 cv_destroy(&dm2sp->ms_wait);
667 ddi_set_driver_private(dm2sp->ms_dip, NULL);
668 ddi_soft_state_free(dm2s_softstate, dm2sp->ms_ppa);
669 }
670
671 /*
672 * dm2s_mbox_init - Mailbox specific initialization.
673 */
674 static int
dm2s_mbox_init(dm2s_t * dm2sp)675 dm2s_mbox_init(dm2s_t *dm2sp)
676 {
677 int ret;
678 clock_t tout = drv_usectohz(DM2S_MB_TOUT);
679
680 ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
681 dm2sp->ms_target = DM2S_TARGET_ID;
682 dm2sp->ms_key = DSCP_KEY;
683 dm2sp->ms_state &= ~DM2S_MB_INITED;
684
685 /* Iterate until mailbox gets connected */
686 while (!(dm2sp->ms_state & DM2S_MB_CONN)) {
687 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: calling mb_init\n"));
688 ret = scf_mb_init(dm2sp->ms_target, dm2sp->ms_key,
689 dm2s_event_handler, (void *)dm2sp);
690 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret));
691
692 if (ret != 0) {
693 DPRINTF(DBG_MBOX,
694 ("dm2s_mbox_init: failed ret =%d\n", ret));
695 DTRACE_PROBE1(dm2s_mbox_fail, int, ret);
696 } else {
697 dm2sp->ms_state |= DM2S_MB_INITED;
698
699 /* Block until the mailbox is ready to communicate. */
700 while (!(dm2sp->ms_state &
701 (DM2S_MB_CONN | DM2S_MB_DISC))) {
702
703 if (cv_wait_sig(&dm2sp->ms_wait,
704 &dm2sp->ms_lock) <= 0) {
705 /* interrupted */
706 ret = EINTR;
707 break;
708 }
709 }
710 }
711
712 if ((ret != 0) || (dm2sp->ms_state & DM2S_MB_DISC)) {
713
714 if (dm2sp->ms_state & DM2S_MB_INITED) {
715 (void) scf_mb_fini(dm2sp->ms_target,
716 dm2sp->ms_key);
717 }
718 if (dm2sp->ms_state & DM2S_MB_DISC) {
719 DPRINTF(DBG_WARN,
720 ("dm2s_mbox_init: mbox DISC_ERROR\n"));
721 DTRACE_PROBE1(dm2s_mbox_fail,
722 int, DM2S_MB_DISC);
723 }
724
725 dm2sp->ms_state &= ~(DM2S_MB_INITED | DM2S_MB_DISC |
726 DM2S_MB_CONN);
727
728 if (ret == EINTR) {
729 return (ret);
730 }
731
732 /*
733 * If there was failure, then wait for
734 * DM2S_MB_TOUT secs and retry again.
735 */
736
737 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: waiting...\n"));
738 ret = cv_reltimedwait_sig(&dm2sp->ms_wait,
739 &dm2sp->ms_lock, tout, TR_CLOCK_TICK);
740 if (ret == 0) {
741 /* if interrupted, return immediately. */
742 DPRINTF(DBG_MBOX,
743 ("dm2s_mbox_init: interrupted\n"));
744 return (EINTR);
745 }
746 }
747 }
748
749 /*
750 * Obtain the max size of a single message.
751 * NOTE: There is no mechanism to update the
752 * upperlayers dynamically, so we expect this
753 * size to be atleast the default MTU size.
754 */
755 ret = scf_mb_ctrl(dm2sp->ms_target, dm2sp->ms_key,
756 SCF_MBOP_MAXMSGSIZE, &dm2sp->ms_mtu);
757
758 if ((ret == 0) && (dm2sp->ms_mtu < DM2S_DEF_MTU)) {
759 cmn_err(CE_WARN, "Max message size expected >= %d "
760 "but found %d\n", DM2S_DEF_MTU, dm2sp->ms_mtu);
761 ret = EIO;
762 }
763
764 if (ret != 0) {
765 dm2sp->ms_state &= ~DM2S_MB_INITED;
766 (void) scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
767 }
768 DPRINTF(DBG_MBOX, ("dm2s_mbox_init: mb_init ret=%d\n", ret));
769 return (ret);
770 }
771
772 /*
773 * dm2s_mbox_fini - Mailbox de-initialization.
774 */
775 static void
dm2s_mbox_fini(dm2s_t * dm2sp)776 dm2s_mbox_fini(dm2s_t *dm2sp)
777 {
778 int ret;
779
780 ASSERT(dm2sp != NULL);
781 if (dm2sp->ms_state & DM2S_MB_INITED) {
782 DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: calling mb_fini\n"));
783 ret = scf_mb_fini(dm2sp->ms_target, dm2sp->ms_key);
784 if (ret != 0) {
785 cmn_err(CE_WARN,
786 "Failed to close the Mailbox error =%d", ret);
787 }
788 DPRINTF(DBG_MBOX, ("dm2s_mbox_fini: mb_fini ret=%d\n", ret));
789 dm2sp->ms_state &= ~(DM2S_MB_INITED |DM2S_MB_CONN |
790 DM2S_MB_DISC);
791 }
792 }
793
794 /*
795 * dm2s_event_handler - Mailbox event handler.
796 */
797 void
dm2s_event_handler(scf_event_t event,void * arg)798 dm2s_event_handler(scf_event_t event, void *arg)
799 {
800 dm2s_t *dm2sp = (dm2s_t *)arg;
801 queue_t *rq;
802
803 ASSERT(dm2sp != NULL);
804 mutex_enter(&dm2sp->ms_lock);
805 if (!(dm2sp->ms_state & DM2S_MB_INITED)) {
806 /*
807 * Ignore all events if the state flag indicates that the
808 * mailbox not initialized, this may happen during the close.
809 */
810 mutex_exit(&dm2sp->ms_lock);
811 DPRINTF(DBG_MBOX,
812 ("Event(0x%X) received - Mailbox not inited\n", event));
813 return;
814 }
815 switch (event) {
816 case SCF_MB_CONN_OK:
817 /*
818 * Now the mailbox is ready to use, lets wake up
819 * any one waiting for this event.
820 */
821 dm2sp->ms_state |= DM2S_MB_CONN;
822 cv_broadcast(&dm2sp->ms_wait);
823 DPRINTF(DBG_MBOX, ("Event received = CONN_OK\n"));
824 break;
825
826 case SCF_MB_MSG_DATA:
827 if (!DM2S_MBOX_READY(dm2sp)) {
828 DPRINTF(DBG_MBOX,
829 ("Event(MSG_DATA) received - Mailbox not READY\n"));
830 break;
831 }
832 /*
833 * A message is available in the mailbox.
834 * Lets enable the read service procedure
835 * to receive this message.
836 */
837 if (dm2sp->ms_rq != NULL) {
838 qenable(dm2sp->ms_rq);
839 }
840 DPRINTF(DBG_MBOX, ("Event received = MSG_DATA\n"));
841 break;
842
843 case SCF_MB_SPACE:
844 if (!DM2S_MBOX_READY(dm2sp)) {
845 DPRINTF(DBG_MBOX,
846 ("Event(MB_SPACE) received - Mailbox not READY\n"));
847 break;
848 }
849
850 /*
851 * Now the mailbox is ready to transmit, lets
852 * schedule the write service procedure.
853 */
854 if (dm2sp->ms_wq != NULL) {
855 qenable(dm2sp->ms_wq);
856 }
857 DPRINTF(DBG_MBOX, ("Event received = MB_SPACE\n"));
858 break;
859 case SCF_MB_DISC_ERROR:
860 dm2sp->ms_state |= DM2S_MB_DISC;
861 if (dm2sp->ms_state & DM2S_MB_CONN) {
862 /*
863 * If it was previously connected,
864 * then send a hangup message.
865 */
866 rq = dm2sp->ms_rq;
867 if (rq != NULL) {
868 mutex_exit(&dm2sp->ms_lock);
869 /*
870 * Send a hangup message to indicate
871 * disconnect event.
872 */
873 (void) putctl(rq, M_HANGUP);
874 DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
875 mutex_enter(&dm2sp->ms_lock);
876 }
877 } else {
878 /*
879 * Signal if the open is waiting for a
880 * connection.
881 */
882 cv_broadcast(&dm2sp->ms_wait);
883 }
884 DPRINTF(DBG_MBOX, ("Event received = DISC_ERROR\n"));
885 break;
886 default:
887 cmn_err(CE_WARN, "Unexpected event received\n");
888 break;
889 }
890 mutex_exit(&dm2sp->ms_lock);
891 }
892
893 /*
894 * dm2s_start - Start transmission function.
895 *
896 * Send all queued messages. If the mailbox is busy, then
897 * start a timeout as a polling mechanism. The timeout is useful
898 * to not rely entirely on the SCF_MB_SPACE event.
899 */
900 void
dm2s_start(queue_t * wq,dm2s_t * dm2sp)901 dm2s_start(queue_t *wq, dm2s_t *dm2sp)
902 {
903 mblk_t *mp;
904 int ret;
905
906 DPRINTF(DBG_DRV, ("dm2s_start: called\n"));
907 ASSERT(dm2sp != NULL);
908 ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
909
910 while ((mp = getq(wq)) != NULL) {
911 switch (mp->b_datap->db_type) {
912
913 case M_DATA:
914 ret = dm2s_transmit(wq, mp, dm2sp->ms_target,
915 dm2sp->ms_key);
916 if (ret == EBUSY || ret == ENOSPC || ret == EAGAIN) {
917 DPRINTF(DBG_MBOX,
918 ("dm2s_start: recoverable err=%d\n", ret));
919 /*
920 * Start a timeout to retry again.
921 */
922 if (dm2sp->ms_wq_timeoutid == 0) {
923 DTRACE_PROBE1(dm2s_wqtimeout__start,
924 dm2s_t, dm2sp);
925 dm2sp->ms_wq_timeoutid = qtimeout(wq,
926 dm2s_wq_timeout, (void *)dm2sp,
927 dm2s_timeout_val(ret));
928 }
929 return;
930 } else if (ret != 0) {
931 mutex_exit(&dm2sp->ms_lock);
932 /*
933 * An error occurred with the transmission,
934 * flush pending messages and initiate a
935 * hangup.
936 */
937 flushq(wq, FLUSHDATA);
938 (void) putnextctl(RD(wq), M_HANGUP);
939 DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
940 DPRINTF(DBG_WARN,
941 ("dm2s_start: hangup transmit err=%d\n",
942 ret));
943 mutex_enter(&dm2sp->ms_lock);
944 }
945 break;
946 default:
947 /*
948 * At this point, we don't expect any other messages.
949 */
950 freemsg(mp);
951 break;
952 }
953 }
954 }
955
956 /*
957 * dm2s_receive - Read all messages from the mailbox.
958 *
959 * This function is called from the read service procedure, to
960 * receive the messages awaiting in the mailbox.
961 */
962 void
dm2s_receive(dm2s_t * dm2sp)963 dm2s_receive(dm2s_t *dm2sp)
964 {
965 queue_t *rq = dm2sp->ms_rq;
966 mblk_t *mp;
967 int ret;
968 uint32_t len;
969
970 DPRINTF(DBG_DRV, ("dm2s_receive: called\n"));
971 ASSERT(dm2sp != NULL);
972 ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
973 if (rq == NULL) {
974 return;
975 }
976 /*
977 * As the number of messages in the mailbox are pretty limited,
978 * it is safe to process all messages in one loop.
979 */
980 while (DM2S_MBOX_READY(dm2sp) && ((ret = scf_mb_canget(dm2sp->ms_target,
981 dm2sp->ms_key, &len)) == 0)) {
982 DPRINTF(DBG_MBOX, ("dm2s_receive: mb_canget len=%d\n", len));
983 if (len == 0) {
984 break;
985 }
986 mp = allocb(len, BPRI_MED);
987 if (mp == NULL) {
988 DPRINTF(DBG_WARN, ("dm2s_receive: allocb failed\n"));
989 /*
990 * Start a bufcall so that we can retry again
991 * when memory becomes available.
992 */
993 dm2sp->ms_rbufcid = qbufcall(rq, len, BPRI_MED,
994 dm2s_bufcall_rcv, dm2sp);
995 if (dm2sp->ms_rbufcid == 0) {
996 DPRINTF(DBG_WARN,
997 ("dm2s_receive: qbufcall failed\n"));
998 /*
999 * if bufcall fails, start a timeout to
1000 * initiate a re-try after some time.
1001 */
1002 DTRACE_PROBE1(dm2s_rqtimeout__start,
1003 dm2s_t, dm2sp);
1004 dm2sp->ms_rq_timeoutid = qtimeout(rq,
1005 dm2s_rq_timeout, (void *)dm2sp,
1006 drv_usectohz(DM2S_SM_TOUT));
1007 }
1008 break;
1009 }
1010
1011 /*
1012 * Only a single scatter/gather element is enough here.
1013 */
1014 dm2sp->ms_sg_rcv.msc_dptr = (caddr_t)mp->b_wptr;
1015 dm2sp->ms_sg_rcv.msc_len = len;
1016 DPRINTF(DBG_MBOX, ("dm2s_receive: calling getmsg\n"));
1017 ret = scf_mb_getmsg(dm2sp->ms_target, dm2sp->ms_key, len, 1,
1018 &dm2sp->ms_sg_rcv, 0);
1019 DPRINTF(DBG_MBOX, ("dm2s_receive: getmsg ret=%d\n", ret));
1020 if (ret != 0) {
1021 freemsg(mp);
1022 break;
1023 }
1024 DMPBYTES("dm2s: Getmsg: ", len, 1, &dm2sp->ms_sg_rcv);
1025 mp->b_wptr += len;
1026 /*
1027 * Queue the messages in the rq, so that the service
1028 * procedure handles sending the messages up the stream.
1029 */
1030 (void) putq(rq, mp);
1031 }
1032
1033 if ((!DM2S_MBOX_READY(dm2sp)) || (ret != ENOMSG && ret != EMSGSIZE)) {
1034 /*
1035 * Some thing went wrong, flush pending messages
1036 * and initiate a hangup.
1037 * Note: flushing the wq initiates a faster close.
1038 */
1039 mutex_exit(&dm2sp->ms_lock);
1040 flushq(WR(rq), FLUSHDATA);
1041 (void) putnextctl(rq, M_HANGUP);
1042 DTRACE_PROBE1(dm2s_hangup, dm2s_t, dm2sp);
1043 mutex_enter(&dm2sp->ms_lock);
1044 DPRINTF(DBG_WARN, ("dm2s_receive: encountered unknown "
1045 "condition - hangup ret=%d\n", ret));
1046 }
1047 }
1048
1049 /*
1050 * dm2s_transmit - Transmit a message.
1051 */
1052 int
dm2s_transmit(queue_t * wq,mblk_t * mp,target_id_t target,mkey_t key)1053 dm2s_transmit(queue_t *wq, mblk_t *mp, target_id_t target, mkey_t key)
1054 {
1055 dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr;
1056 int ret;
1057 uint32_t len;
1058 uint32_t numsg;
1059
1060 DPRINTF(DBG_DRV, ("dm2s_transmit: called\n"));
1061 ASSERT(dm2sp != NULL);
1062 ASSERT(MUTEX_HELD(&dm2sp->ms_lock));
1063 /*
1064 * Free the message if the mailbox is not in the connected state.
1065 */
1066 if (!DM2S_MBOX_READY(dm2sp)) {
1067 DPRINTF(DBG_MBOX, ("dm2s_transmit: mailbox not ready yet\n"));
1068 freemsg(mp);
1069 return (EIO);
1070 }
1071
1072 len = msgdsize(mp);
1073 if (len > dm2sp->ms_mtu) {
1074 /*
1075 * Size is too big to send, free the message.
1076 */
1077 DPRINTF(DBG_MBOX, ("dm2s_transmit: message too large\n"));
1078 DTRACE_PROBE2(dm2s_msg_too_big, dm2s_t, dm2sp, uint32_t, len);
1079 freemsg(mp);
1080 return (0);
1081 }
1082
1083 if ((ret = dm2s_prep_scatgath(mp, &numsg, dm2sp->ms_sg_tx,
1084 DM2S_MAX_SG)) != 0) {
1085 DPRINTF(DBG_MBOX, ("dm2s_transmit: prep_scatgath failed\n"));
1086 (void) putbq(wq, mp);
1087 return (EAGAIN);
1088 }
1089 DPRINTF(DBG_MBOX, ("dm2s_transmit: calling mb_putmsg numsg=%d len=%d\n",
1090 numsg, len));
1091 ret = scf_mb_putmsg(target, key, len, numsg, dm2sp->ms_sg_tx, 0);
1092 if (ret == EBUSY || ret == ENOSPC) {
1093 DPRINTF(DBG_MBOX,
1094 ("dm2s_transmit: mailbox busy ret=%d\n", ret));
1095 if (++dm2sp->ms_retries >= DM2S_MAX_RETRIES) {
1096 /*
1097 * If maximum retries are reached, then free the
1098 * message.
1099 */
1100 DPRINTF(DBG_MBOX,
1101 ("dm2s_transmit: freeing msg after max retries\n"));
1102 DTRACE_PROBE2(dm2s_retry_fail, dm2s_t, dm2sp, int, ret);
1103 freemsg(mp);
1104 dm2sp->ms_retries = 0;
1105 return (0);
1106 }
1107 DTRACE_PROBE2(dm2s_mb_busy, dm2s_t, dm2sp, int, ret);
1108 /*
1109 * Queue it back, so that we can retry again.
1110 */
1111 (void) putbq(wq, mp);
1112 return (ret);
1113 }
1114 DMPBYTES("dm2s: Putmsg: ", len, numsg, dm2sp->ms_sg_tx);
1115 dm2sp->ms_retries = 0;
1116 freemsg(mp);
1117 DPRINTF(DBG_DRV, ("dm2s_transmit: ret=%d\n", ret));
1118 return (ret);
1119 }
1120
1121 /*
1122 * dm2s_bufcall_rcv - Bufcall callaback routine.
1123 *
1124 * It simply enables read side queue so that the service procedure
1125 * can retry receive operation.
1126 */
1127 void
dm2s_bufcall_rcv(void * arg)1128 dm2s_bufcall_rcv(void *arg)
1129 {
1130 dm2s_t *dm2sp = (dm2s_t *)arg;
1131
1132 DPRINTF(DBG_DRV, ("dm2s_bufcall_rcv: called\n"));
1133 mutex_enter(&dm2sp->ms_lock);
1134 dm2sp->ms_rbufcid = 0;
1135 if (dm2sp->ms_rq != NULL) {
1136 qenable(dm2sp->ms_rq);
1137 }
1138 mutex_exit(&dm2sp->ms_lock);
1139 }
1140
1141 /*
1142 * dm2s_rq_timeout - Timeout callback for the read side.
1143 *
1144 * It simply enables read side queue so that the service procedure
1145 * can retry the receive operation.
1146 */
1147 void
dm2s_rq_timeout(void * arg)1148 dm2s_rq_timeout(void *arg)
1149 {
1150 dm2s_t *dm2sp = (dm2s_t *)arg;
1151
1152 DPRINTF(DBG_DRV, ("dm2s_rq_timeout: called\n"));
1153 mutex_enter(&dm2sp->ms_lock);
1154 dm2sp->ms_rq_timeoutid = 0;
1155 if (dm2sp->ms_rq != NULL) {
1156 qenable(dm2sp->ms_rq);
1157 }
1158 mutex_exit(&dm2sp->ms_lock);
1159 }
1160
1161 /*
1162 * dm2s_wq_timeout - Timeout callback for the write.
1163 *
1164 * It simply enables write side queue so that the service procedure
1165 * can retry the transmission operation.
1166 */
1167 void
dm2s_wq_timeout(void * arg)1168 dm2s_wq_timeout(void *arg)
1169 {
1170 dm2s_t *dm2sp = (dm2s_t *)arg;
1171
1172 DPRINTF(DBG_DRV, ("dm2s_wq_timeout: called\n"));
1173 mutex_enter(&dm2sp->ms_lock);
1174 dm2sp->ms_wq_timeoutid = 0;
1175 if (dm2sp->ms_wq != NULL) {
1176 qenable(dm2sp->ms_wq);
1177 }
1178 mutex_exit(&dm2sp->ms_lock);
1179 }
1180
1181 /*
1182 * dm2s_prep_scatgath - Prepare scatter/gather elements for transmission
1183 * of a streams message.
1184 */
1185 static int
dm2s_prep_scatgath(mblk_t * mp,uint32_t * numsg,mscat_gath_t * sgp,int maxsg)1186 dm2s_prep_scatgath(mblk_t *mp, uint32_t *numsg, mscat_gath_t *sgp, int maxsg)
1187 {
1188 uint32_t num = 0;
1189 mblk_t *tmp = mp;
1190
1191 while ((tmp != NULL) && (num < maxsg)) {
1192 sgp[num].msc_dptr = (caddr_t)tmp->b_rptr;
1193 sgp[num].msc_len = MBLKL(tmp);
1194 tmp = tmp->b_cont;
1195 num++;
1196 }
1197
1198 if (tmp != NULL) {
1199 /*
1200 * Number of scatter/gather elements available are not
1201 * enough, so lets pullup the msg.
1202 */
1203 if (pullupmsg(mp, -1) != 1) {
1204 return (EAGAIN);
1205 }
1206 sgp[0].msc_dptr = (caddr_t)mp->b_rptr;
1207 sgp[0].msc_len = MBLKL(mp);
1208 num = 1;
1209 }
1210 *numsg = num;
1211 return (0);
1212 }
1213
1214 /*
1215 * dm2s_timeout_val -- Return appropriate timeout value.
1216 *
1217 * A small timeout value is returned for EBUSY and EAGAIN cases. This is
1218 * because the condition is expected to be recovered sooner.
1219 *
1220 * A larger timeout value is returned for ENOSPC case, as the condition
1221 * depends on the peer to release buffer space.
1222 * NOTE: there will also be an event(SCF_MB_SPACE) but a timeout is
1223 * used for reliability purposes.
1224 */
1225 static clock_t
dm2s_timeout_val(int error)1226 dm2s_timeout_val(int error)
1227 {
1228 clock_t tval;
1229
1230 ASSERT(error == EBUSY || error == ENOSPC || error == EAGAIN);
1231
1232 if (error == EBUSY || error == EAGAIN) {
1233 tval = DM2S_SM_TOUT;
1234 } else {
1235 tval = DM2S_LG_TOUT;
1236 }
1237 return (drv_usectohz(tval));
1238 }
1239
1240 #ifdef DEBUG
1241
1242 static void
dm2s_dump_bytes(char * str,uint32_t total_len,uint32_t num_sg,mscat_gath_t * sgp)1243 dm2s_dump_bytes(char *str, uint32_t total_len,
1244 uint32_t num_sg, mscat_gath_t *sgp)
1245 {
1246 int i, j;
1247 int nsg;
1248 int len, tlen = 0;
1249 mscat_gath_t *tp;
1250 uint8_t *datap;
1251 #define BYTES_PER_LINE 20
1252 char bytestr[BYTES_PER_LINE * 3 + 1];
1253 uint32_t digest = 0;
1254
1255 if (!(dm2s_debug & DBG_MESG))
1256 return;
1257 ASSERT(num_sg != 0);
1258
1259 for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) {
1260 tp = &sgp[nsg];
1261 datap = (uint8_t *)tp->msc_dptr;
1262 len = tp->msc_len;
1263 for (i = 0; i < len; i++) {
1264 digest += datap[i];
1265 }
1266 tlen += len;
1267 }
1268 (void) sprintf(bytestr, "%s Packet: Size=%d Digest=%d\n",
1269 str, total_len, digest);
1270 DTRACE_PROBE1(dm2s_dump_digest, unsigned char *, bytestr);
1271
1272 tlen = 0;
1273 for (nsg = 0; (nsg < num_sg) && (tlen < total_len); nsg++) {
1274 tp = &sgp[nsg];
1275 datap = (uint8_t *)tp->msc_dptr;
1276 len = tp->msc_len;
1277 for (i = 0; i < len; ) {
1278 for (j = 0; (j < BYTES_PER_LINE) &&
1279 (i < len); j++, i++) {
1280 (void) sprintf(&bytestr[j * 3], "%02X ",
1281 datap[i]);
1282 digest += datap[i];
1283 }
1284 if (j != 0) {
1285 DTRACE_PROBE1(dm2s_dump, unsigned char *,
1286 bytestr);
1287 }
1288 }
1289 tlen += i;
1290 }
1291 }
1292
1293 #endif /* DEBUG */
1294