|
|
1.1 root 1: /*
2: * DSA disk class driver
3: * drives RA-class disks
4: * hooked up through an MSCP port
5: */
6:
7: #include "sys/param.h"
8: #include "sys/buf.h"
9: #include "sys/udaioc.h"
10: #include "sys/diskio.h"
11: #include "sys/ra.h"
12: #include "sys/mscp.h"
13: #include "sys/user.h"
14: #include "sys/file.h"
15: #include "sys/conf.h"
16:
17: extern struct msaddr raaddr[];
18: extern struct radisk radisk[];
19: extern int racnt;
20: static long rarefno; /* ref seq num */
21: extern struct buf rabuf[];
22: static struct buf rctbuf; /* for reading replacement table */
23:
24: static rareplace(), raonline(), rasonl(), racinit();
25:
26: int raopen(), raread(), rawrite(), raioctl(), rastrategy(), raclose();
27: struct bdevsw rabdev = bdinit(raopen, raclose, rastrategy, 0);
28: struct cdevsw racdev = cdinit(raopen, raclose, raread, rawrite, raioctl);
29:
30: /*
31: * UNIT(d) == logical unit number;
32: * the physical unit number is in raaddr[UNIT(d)].unit
33: *
34: * 0100 in the minor device is (temporarily?)
35: * usurped to indicate bitmapped file systems
36: * quietly ignore it for now
37: * when things improve, change the UNIT mask to 037
38: */
39: #define UNIT(dev) (((dev)>>3) & 027)
40: #define PART(dev) ((dev)&07)
41: #define HUGE 0x7fffffff /* very large 32-bit number */
42:
43: /*
44: * default partition sizes
45: */
46: static struct size {
47: daddr_t nblocks;
48: daddr_t blkoff;
49: } ra_sizes[NRAPART] = {
50: 10240, 0,
51: 20480, 10240,
52: 249848, 30720,
53: 249848, 280568,
54: 249848, 530416,
55: HUGE, 780264,
56: 749544, 30720, /* slices 2,3,4 */
57: HUGE, 0, /* whole drive */
58: };
59:
60: /*
61: * reused bits of buf/iobuf struct
62: */
63:
64: #define b_next av_forw /* next buffer in queue */
65: #define b_pkt av_back /* pointer to mscp command */
66: #define b_crf b_resid /* saved refno for pending command */
67:
68: /*
69: * flags in radisk.flags
70: */
71:
72: #define ONLINE 01 /* drive is online */
73: #define WONLINE 02 /* waiting for online */
74: #define GOTDI 04 /* got unit info */
75: #define RPLOCK 010 /* replacement in progress */
76: #define RPWANT 020 /* want RPLOCK */
77: #define RPDONE 040 /* replacement done */
78: #define SPDOWN 0100 /* spin down on last close */
79:
80: /*
81: * random numbers
82: */
83:
84: #define PRIONL (PZERO-1)
85: #define SECTOR 512 /* size of an MSCP sector */
86: #define IDRA 0 /* connection ID for MSCP */
87:
88: /*
89: * open a drive, if necessary
90: */
91:
92: int raseql(), radg();
93:
94: raopen(dev, flag)
95: dev_t dev;
96: {
97: register int unit;
98: register struct radisk *ra;
99: register struct msaddr *rp;
100: register int part;
101:
102: unit = UNIT(dev);
103: if (unit >= racnt) {
104: u.u_error = ENXIO;
105: return;
106: }
107: ra = &radisk[unit];
108: rp = &raaddr[unit];
109: if (ra->open == 0) {
110: if (rp->ctype < 0 || rp->ctype >= nmsport
111: || (ra->port = msportsw[rp->ctype]) == NULL) {
112: u.u_error = ENXIO;
113: return;
114: }
115: ra->di.radsize = HUGE;
116: if ((*ra->port->mp_init)(rp->ctl, rp->ctype, 0, IDRA, raseql, radg) == 0) {
117: u.u_error = ENXIO;
118: return;
119: }
120: racinit(ra, rp);
121: }
122: part = PART(dev);
123: if ((ra->pinit & (1<<part)) == 0) {
124: ra->nblocks[part] = ra_sizes[part].nblocks;
125: ra->blkoff[part] = ra_sizes[part].blkoff;
126: ra->pinit |= (1<<part);
127: }
128: ra->open |= 1<<part;
129: spl6();
130: if ((ra->flags & ONLINE) == 0)
131: raonline(ra, rp);
132: spl0();
133: if ((ra->flags & ONLINE) == 0)
134: u.u_error = ENXIO;
135: }
136:
137: raclose(dev)
138: {
139: register struct radisk *ra;
140: register struct msaddr *rp;
141: register struct mscmd *mp;
142:
143: ra = &radisk[UNIT(dev)];
144: rp = &raaddr[UNIT(dev)];
145: ra->open &=~ (1<<PART(dev));
146: if (ra->open || (ra->flags & ONLINE) == 0)
147: return;
148: mp = (*ra->port->mp_get)(rp->ctl);
149: mp->m_crf = ++rarefno;
150: mp->m_unit = rp->unit;
151: mp->m_opcd = OPAVL; /* put it offline */
152: if ((ra->flags & SPDOWN) == 0)
153: mp->m_mod = 0;
154: else {
155: mp->m_mod = MDSPD;
156: ra->flags &=~ SPDOWN;
157: }
158: mp->m_unfl = 0;
159: mp->m_dvpm = 0; /* ? */
160: ra->flags &=~ ONLINE;
161: (*ra->port->mp_send)(rp->ctl, IDRA, mp);
162: }
163:
164: int rastrategy();
165:
166: raread(dev)
167: {
168: physio(rastrategy, &rabuf[UNIT(dev)], dev, B_READ, minphys);
169: }
170:
171: rawrite(dev)
172: {
173: physio(rastrategy, &rabuf[UNIT(dev)], dev, B_WRITE, minphys);
174: }
175:
176: /*
177: * strategy routine;
178: * used as strategy by all port drivers
179: * send the packet right away
180: */
181:
182: rastrategy(bp)
183: register struct buf *bp;
184: {
185: register struct radisk *ra;
186: register struct mscmd *mp;
187: register int unit;
188: register int part;
189: register struct msaddr *rp;
190: int count;
191: daddr_t limit;
192:
193: unit = UNIT(minor(bp->b_dev));
194: part = PART(minor(bp->b_dev));
195: ra = &radisk[unit];
196: rp = &raaddr[unit];
197: limit = ra->di.radsize - ra->blkoff[part];
198: if (limit > ra->nblocks[part])
199: limit = ra->nblocks[part];
200: if (bp->b_blkno >= limit && bp != &rctbuf) {
201: if (bp->b_blkno == ra->nblocks[part])
202: bp->b_resid = bp->b_bcount;
203: else {
204: bp->b_error = ENOSPC;
205: bp->b_flags |= B_ERROR;
206: }
207: iodone(bp);
208: return;
209: }
210: count = bp->b_bcount;
211: if (count/SECTOR + bp->b_blkno > limit && bp != &rctbuf)
212: count = (limit - bp->b_blkno) * SECTOR;
213: spl6();
214: if ((ra->flags & ONLINE) == 0 && raonline(ra, rp) == 0) {
215: bp->b_flags |= B_ERROR;
216: iodone(bp);
217: spl0();
218: return;
219: }
220: mp = (*ra->port->mp_get)(rp->ctl);
221: mp->m_crf = ++rarefno;
222: mp->m_unit = rp->unit;
223: mp->m_opcd = (bp->b_flags & B_READ) ? OPRD : OPWR;
224: mp->m_mod = 0;
225: mp->m_bcnt = count;
226: mp->m_lbn = bp->b_blkno + ra->blkoff[part];
227: (*ra->port->mp_map)(rp->ctl, mp, bp);
228: bp->b_pkt = (struct buf *)mp;
229: bp->b_crf = mp->m_crf;
230: bp->b_next = NULL;
231: if (ra->actf)
232: ra->actl->b_next = bp;
233: else
234: ra->actf = bp;
235: ra->actl = bp;
236: (*ra->port->mp_send)(rp->ctl, IDRA, mp);
237: spl0();
238: }
239:
240: /*
241: * ioctl
242: * principally for bad block replacement
243: */
244:
245: raioctl(dev, cmd, addr, flag)
246: dev_t dev;
247: caddr_t addr;
248: {
249: register union arg {
250: struct ud_rctbuf r;
251: struct ud_repl b;
252: } *uap;
253: register struct radisk *ra;
254: register int i;
255: long parts[2];
256:
257: ra = &radisk[UNIT(dev)];
258: if ((ra->flags & (ONLINE|GOTDI)) != (ONLINE|GOTDI)) {
259: /* should bring it online here */
260: u.u_error = EIO;
261: return;
262: }
263: uap = (union arg *)addr;
264: switch(cmd) {
265: default:
266: u.u_error = ENOTTY;
267: return;
268:
269: case DIOSSIZ:
270: if ((flag & FWRITE) == 0) {
271: u.u_error = EBADF;
272: return;
273: }
274: if (copyin(addr, (caddr_t)parts, sizeof(parts)) < 0) {
275: u.u_error = EFAULT;
276: return;
277: }
278: ra->blkoff[PART(dev)] = parts[0];
279: ra->nblocks[PART(dev)] = parts[1];
280: return;
281:
282: case DIOGSIZ:
283: parts[0] = ra->blkoff[PART(dev)];
284: parts[1] = ra->nblocks[PART(dev)];
285: if (copyout((caddr_t)parts, addr, sizeof(parts)) < 0)
286: u.u_error = EFAULT;
287: return;
288:
289: case UIOCHAR:
290: if (copyout((caddr_t)&ra->di, addr, sizeof(struct ud_unit)))
291: u.u_error = EFAULT;
292: return;
293:
294: case UIORRCT:
295: if(uap->r.lbn < 0 || uap->r.lbn > ra->di.rctsize) {
296: u.u_error = EIO;
297: return;
298: }
299: /*
300: * try different copies until one works
301: */
302: for (i = 0; i < ra->di.copies; i++) {
303: u.u_count = SECTOR; /* block size on disk */
304: u.u_offset = ltoL((uap->r.lbn + ra->di.radsize) * SECTOR);
305: u.u_offset = Lladd(u.u_offset,i * ra->di.rctsize * SECTOR);
306: u.u_base = uap->r.buf;
307: u.u_segflg = SEGUDATA;
308: u.u_error = 0;
309: physio(rastrategy, &rctbuf, dev, B_READ, minphys);
310: if (u.u_error == 0)
311: break;
312: }
313: return;
314:
315: case UIOWRCT:
316: if ((flag & FWRITE) == 0) {
317: u.u_error = EBADF;
318: return;
319: }
320: if(uap->r.lbn < 0 || uap->r.lbn > ra->di.rctsize) {
321: u.u_error = EIO;
322: return;
323: }
324: /*
325: * write every copy we can
326: * should do read-after-write
327: */
328: for (i = 0; i < ra->di.copies; i++) {
329: u.u_count = SECTOR; /* block size on disk */
330: u.u_offset = ltoL((uap->r.lbn + ra->di.radsize) * SECTOR);
331: u.u_offset = Lladd(u.u_offset, i * ra->di.rctsize * SECTOR);
332: u.u_base = uap->r.buf;
333: u.u_segflg = SEGUDATA;
334: physio(rastrategy, &rctbuf, dev, B_WRITE, minphys);
335: u.u_error = 0;
336: }
337: return;
338:
339: case UIOREPL:
340: if ((flag & FWRITE) == 0) {
341: u.u_error = EBADF;
342: return;
343: }
344: rareplace(dev, uap->b.lbn, uap->b.replbn, uap->b.prim);
345: return;
346:
347: case UIOSPDW:
348: ra->flags |= SPDOWN;
349: return;
350:
351: case UIORST:
352: (*ra->port->mp_init)(raaddr[UNIT(dev)].ctl, raaddr[UNIT(dev)].ctype, 1, IDRA, raseql, radg);
353: return;
354: }
355:
356: }
357:
358: static
359: rareplace(dev, badlbn, replbn, prim)
360: int dev;
361: daddr_t badlbn;
362: daddr_t replbn;
363: int prim;
364: {
365: register struct mscmd *mp;
366: register struct radisk *ra;
367: register struct msaddr *rp;
368: register int unit;
369:
370: unit = UNIT(minor(dev));
371: ra = &radisk[unit];
372: rp = &raaddr[unit];
373: spl6();
374: while (ra->flags & RPLOCK) {
375: ra->flags |= RPWANT;
376: sleep((caddr_t)&ra->flags, PZERO + 1);
377: }
378: ra->flags |= RPLOCK;
379: printf("ra%d replace %D with %D\n", unit, badlbn, replbn);
380: mp = (*ra->port->mp_get)(rp->ctl);
381: bzero((caddr_t)mp, sizeof(struct mscmd)); /* clear reserved fields */
382: mp->m_crf = ++rarefno;
383: mp->m_unit = rp->unit;
384: mp->m_opcd = OPRPL;
385: mp->m_rbn = replbn;
386: mp->m_lbn = badlbn;
387: mp->m_mod = prim ? MDPRI : 0;
388: ra->cmdcrf = mp->m_crf;
389: ra->cmdopc = OPRPL;
390: (*ra->port->mp_send)(rp->ctl, IDRA, mp);
391: while ((ra->flags & RPDONE) == 0)
392: sleep((caddr_t)&ra->rplret, PZERO);
393: u.u_error = ra->rplret;
394: if (ra->flags & RPWANT)
395: wakeup((caddr_t)&ra->flags);
396: ra->flags &=~ (RPWANT|RPLOCK|RPDONE);
397: spl0();
398:
399: }
400:
401: /*
402: * here when the port gets a sequential message
403: */
404: raseql(ctl, type, ep)
405: int ctl, type;
406: register struct msend *ep;
407: {
408: register struct buf *bp;
409: register struct radisk *ra;
410: register int unit;
411: register struct buf *obp;
412: int sts;
413:
414: if (ep->m_opcd == 0 && ep->m_sts == STRST) {
415: rareset(ctl);
416: return;
417: }
418: for (unit = 0; unit < racnt; unit++)
419: if (raaddr[unit].ctl == ctl
420: && raaddr[unit].ctype == type
421: && raaddr[unit].unit == ep->m_unit)
422: break;
423: if (unit >= racnt) {
424: printf("ra%d ctl%d typ%d: stray mscp packet sts x%x opcode %o\n",
425: ep->m_unit, ctl, type, ep->m_sts, ep->m_opcd);
426: return;
427: }
428: ra = &radisk[unit];
429: sts = ep->m_sts & STMSK;
430: if (sts == STAVL || sts == STOFL)
431: ra->flags &=~ ONLINE; /* help! */
432: illcmd:
433: switch (ep->m_opcd & 0377) {
434: case OPEND: /* eg invalid command */
435: if (ep->m_crf == ra->cmdcrf) {
436: ep->m_opcd = ra->cmdopc | OPEND;
437: goto illcmd;
438: }
439: /* else check for pending read or write */
440: case OPRD|OPEND:
441: case OPWR|OPEND:
442: for (bp = ra->actf, obp = NULL; bp; obp = bp, bp = bp->b_next)
443: if (ep->m_crf == bp->b_crf)
444: break;
445: if (bp == NULL) {
446: printf("ra%d stray end: crf %d sts x%x opcode 0%o\n",
447: unit, ep->m_crf, ep->m_sts, ep->m_opcd & 0377);
448: return;
449: }
450: if (((struct mscmd *)(bp->b_pkt))->m_crf != ep->m_crf)
451: printf("ra%d sent %d got %d crf; flg %x dev %x\n",
452: unit, ((struct mscmd *)(bp->b_pkt))->m_crf,
453: ep->m_crf, bp->b_flags, bp->b_dev);
454: if (obp)
455: obp->b_next = bp->b_next;
456: else
457: ra->actf = bp->b_next;
458: if (bp == ra->actl)
459: ra->actl = obp;
460: bp->b_resid = bp->b_bcount - ep->m_bcnt;
461: if (sts != STSUC) {
462: bp->b_flags |= B_ERROR;
463: if (ep->m_sts == STBCK || ep->m_sts == STBK2) /* optical disk blank check */
464: bp->b_error = ENXIO;
465: else
466: printf("err on ra%d block %D: sts x%x\n", unit, bp->b_blkno, ep->m_sts);
467: }
468: (*ra->port->mp_unmap)(ctl, (struct mscmd *)bp->b_pkt);
469: iodone(bp);
470: return;
471:
472: case OPONL|OPEND:
473: rasonl(ra, ep);
474: return;
475:
476: case OPAVL|OPEND:
477: ra->flags &=~ ONLINE;
478: return;
479:
480: case OPGUS|OPEND:
481: if (sts != STSUC) {
482: printf("ra%d: can't get unit sts x%x\n", unit, ep->m_sts);
483: return;
484: }
485: ra->di.medium = ep->m_medi;
486: ra->di.tracksz = ep->m_trck;
487: ra->di.groupsz = ep->m_grp;
488: ra->di.cylsz = ep->m_cyl;
489: ra->di.rctsize = ep->m_rcts;
490: ra->di.rbns = ep->m_rbns;
491: ra->di.copies = ep->m_rctc;
492: ra->flags |= GOTDI;
493: return;
494:
495: case OPSCC|OPEND:
496: if (sts != STSUC)
497: printf("ra ctl%d typ%d: bad init\n", ctl, type);
498: return;
499:
500: case OPRPL|OPEND:
501: ra->rplret = 0;
502: if (sts != STSUC) {
503: printf("ra%d: rpl sts x%x\n", unit, ep->m_sts);
504: ra->rplret = EIO;
505: }
506: ra->flags |= RPDONE;
507: wakeup((caddr_t)&ra->rplret);
508: return;
509:
510: default:
511: printf("ra%d ctl%d typ%d: stray mscp msg opcd 0%o sts x%x\n",
512: ep->m_unit, ctl, type, ep->m_opcd&0377, ep->m_sts);
513: return;
514: }
515: }
516:
517: /*
518: * controller was reset
519: * discard all pending io,
520: * awake all sleepers,
521: * mark everything offline
522: */
523:
524: rareset(ctl)
525: int ctl;
526: {
527: register int unit;
528: register struct radisk *ra;
529: register struct buf *bp, *nbp;
530:
531: for (unit = 0; unit < racnt; unit++) {
532: if (raaddr[unit].ctl != ctl)
533: continue;
534: ra = &radisk[unit];
535: for (bp = ra->actf; bp; bp = nbp) {
536: nbp = bp->b_next;
537: (*ra->port->mp_unmap)(ctl, (struct mscmd *)bp->b_pkt);
538: bp->b_flags |= B_ERROR;
539: iodone(bp);
540: }
541: ra->actf = ra->actl = NULL;
542: ra->flags &=~ (ONLINE|WONLINE);
543: wakeup((caddr_t)ra);
544: }
545: }
546:
547: /*
548: * here with a datagram message
549: * explanations really shouldn't be in the driver
550: *
551: * the hack for event 8 ignores error packets from
552: * the US Design optical disk controller
553: * that really mean `read a blank spot on the disk
554: */
555:
556: static char *raevents[] = {
557: "ok",
558: "inv cmd",
559: "op aborted",
560: "offline",
561: "available",
562: "med fmt",
563: "write prot",
564: "comp err",
565: "data err",
566: "host buf access err",
567: "cntl err",
568: "drive err",
569: };
570: #define MAXEVT 0xb
571:
572: radg(ctl, type, ep)
573: int ctl, type;
574: register struct mserl *ep;
575: {
576: register u_short *sp; /* for sdi crap */
577: register int i; /* for useless design crap */
578: register unsigned char *cp; /* for useless design crap */
579:
580: if (ep->l_fmt == FMDSK && ep->l_evnt == STBCK && ep->l_flgs == 0)
581: return;
582: printf("ra%d ctl%d typ%d seq %d: %s err; fmt x%x ev x%x fl x%x\n",
583: ep->l_unit, ctl, type, ep->l_seq, /* phys unit, not log */
584: ep->l_flgs&(LFSUC|LFCON) ? "soft" : "hard",
585: ep->l_fmt, ep->l_evnt, ep->l_flgs&0377);
586: if ((ep->l_evnt & STMSK) <= MAXEVT)
587: printf("%s; ", raevents[ep->l_evnt & STMSK]);
588: switch (ep->l_fmt) {
589: case FMCNT:
590: /* now the thing should be marked disastrously bad */
591: printf("oops\n");
592: break;
593:
594: case FMBAD:
595: printf("host mem access; addr x%x\n", ep->l_badr);
596: break;
597:
598: case FMDSK:
599: printf("%sbn %d; lev x%x, retry x%x\n",
600: (ep->l_hdcd & 0xf0000000) == 0 ? "l" : "r",
601: ep->l_hdcd & 0x0fffffff, ep->l_lvl, ep->l_rtry);
602: break;
603:
604: case FMSDI:
605: printf("%sbn %d;",
606: (ep->l_hdcd & 0xf0000000) == 0 ? "l" : "r",
607: ep->l_hdcd & 0x0fffffff);
608: /*
609: * print the bytes in the same order used
610: * by the dec diagnostics
611: */
612: sp = (u_short *)&ep->l_sdi[3];
613: while (sp > (u_short *)ep->l_sdi)
614: printf(" %x", *--sp);
615: printf(" xx\n");
616: break;
617:
618: case FMSMD:
619: printf("cyl %d\n", ep->l_sdi[1]);
620: break;
621:
622: case 0x40: /* hack for useless design */
623: printf("scsi:");
624: cp = (unsigned char *)ep->l_sdi;
625: for(i = 0; i < 10; i++)
626: printf(" %x", *cp++);
627: printf(" [%x %x]\n", cp[0], cp[1]);
628: break;
629:
630: default:
631: printf("\n");
632: break;
633: }
634: }
635:
636: /*
637: * unit is believed offline
638: * try to bring it on
639: */
640:
641: static
642: raonline(ra, rp)
643: register struct radisk *ra;
644: register struct msaddr *rp;
645: {
646: register struct mscmd *mp;
647: int s;
648:
649: s = spl6();
650: if ((ra->flags & WONLINE) == 0) {
651: ra->flags &=~ GOTDI;
652: mp = (*ra->port->mp_get)(rp->ctl);
653: bzero((caddr_t)mp, sizeof(struct mscmd)); /* clear reserved fields */
654: mp->m_crf = ++rarefno;
655: mp->m_unit = rp->unit;
656: mp->m_opcd = OPONL;
657: ra->cmdcrf = mp->m_crf;
658: ra->cmdopc = OPONL;
659: (*ra->port->mp_send)(rp->ctl, IDRA, mp);
660: ra->flags |= WONLINE;
661: }
662: while (ra->flags & WONLINE)
663: tsleep((caddr_t)ra, PRIONL, 60);
664: if ((ra->flags & ONLINE) == 0)
665: return (0);
666: if ((ra->flags & GOTDI) == 0) {
667: mp = (*ra->port->mp_get)(rp->ctl);
668: mp->m_crf = ++rarefno;
669: mp->m_unit = rp->unit;
670: mp->m_opcd = OPGUS;
671: mp->m_mod = 0;
672: mp->m_unfl = 0;
673: mp->m_dvpm = 0; /* ? */
674: (*ra->port->mp_send)(rp->ctl, IDRA, mp);
675: }
676: splx(s);
677: return (1);
678: }
679:
680: static
681: rasonl(ra, ep)
682: register struct radisk *ra;
683: register struct msend *ep;
684: {
685:
686: if (ra->flags & WONLINE) {
687: ra->flags &=~ WONLINE;
688: wakeup((caddr_t)ra);
689: }
690: if ((ep->m_sts & STMSK) != STSUC)
691: return;
692: ra->flags |= ONLINE;
693: if (ra->di.radsize != HUGE && ra->di.radsize != ep->m_unsz)
694: printf("ra%d: changed size %d to %d\n", ra-radisk, ra->di.radsize, ep->m_unsz);
695: ra->di.radsize = ep->m_unsz;
696: }
697:
698: /*
699: * controller init
700: * set characteristics to turn off host timeouts
701: */
702:
703: static
704: racinit(ra, rp)
705: struct radisk *ra;
706: struct msaddr *rp;
707: {
708: register struct mscmd *mp;
709: register int s;
710:
711: mp = (*ra->port->mp_get)(rp->ctl);
712: mp->m_crf = ++rarefno;
713: mp->m_unit = rp->unit;
714: mp->m_opcd = OPSCC;
715: mp->m_mod = 0;
716: mp->m_cntf = CFMSC | CFTHS;
717: mp->m_vrsn = MSCPVER;
718: mp->m_htmo = 0; /* no timeout */
719: mp->m_time[0] = mp->m_time[1] = 0L;
720: s = spl6();
721: (*ra->port->mp_send)(rp->ctl, IDRA, mp);
722: splx(s);
723: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.