]> CyberLeo.Net >> Repos - FreeBSD/releng/10.1.git/blob - sys/geom/geom_disk.c
MFS10 r273767 / MFC r273638:
[FreeBSD/releng/10.1.git] / sys / geom / geom_disk.c
1 /*-
2  * Copyright (c) 2002 Poul-Henning Kamp
3  * Copyright (c) 2002 Networks Associates Technology, Inc.
4  * All rights reserved.
5  *
6  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7  * and NAI Labs, the Security Research Division of Network Associates, Inc.
8  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9  * DARPA CHATS research program.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The names of the authors may not be used to endorse or promote
20  *    products derived from this software without specific prior written
21  *    permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35
36 #include <sys/cdefs.h>
37 __FBSDID("$FreeBSD$");
38
39 #include "opt_geom.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/sysctl.h>
45 #include <sys/bio.h>
46 #include <sys/ctype.h>
47 #include <sys/fcntl.h>
48 #include <sys/malloc.h>
49 #include <sys/sbuf.h>
50 #include <sys/devicestat.h>
51 #include <machine/md_var.h>
52
53 #include <sys/lock.h>
54 #include <sys/mutex.h>
55 #include <geom/geom.h>
56 #include <geom/geom_disk.h>
57 #include <geom/geom_int.h>
58
59 #include <dev/led/led.h>
60
61 struct g_disk_softc {
62         struct mtx               done_mtx;
63         struct disk             *dp;
64         struct sysctl_ctx_list  sysctl_ctx;
65         struct sysctl_oid       *sysctl_tree;
66         char                    led[64];
67         uint32_t                state;
68         struct mtx               start_mtx;
69 };
70
71 static g_access_t g_disk_access;
72 static g_start_t g_disk_start;
73 static g_ioctl_t g_disk_ioctl;
74 static g_dumpconf_t g_disk_dumpconf;
75 static g_provgone_t g_disk_providergone;
76
77 static struct g_class g_disk_class = {
78         .name = G_DISK_CLASS_NAME,
79         .version = G_VERSION,
80         .start = g_disk_start,
81         .access = g_disk_access,
82         .ioctl = g_disk_ioctl,
83         .providergone = g_disk_providergone,
84         .dumpconf = g_disk_dumpconf,
85 };
86
87 SYSCTL_DECL(_kern_geom);
88 static SYSCTL_NODE(_kern_geom, OID_AUTO, disk, CTLFLAG_RW, 0,
89     "GEOM_DISK stuff");
90
91 DECLARE_GEOM_CLASS(g_disk_class, g_disk);
92
93 static void __inline
94 g_disk_lock_giant(struct disk *dp)
95 {
96
97         if (dp->d_flags & DISKFLAG_NEEDSGIANT)
98                 mtx_lock(&Giant);
99 }
100
101 static void __inline
102 g_disk_unlock_giant(struct disk *dp)
103 {
104
105         if (dp->d_flags & DISKFLAG_NEEDSGIANT)
106                 mtx_unlock(&Giant);
107 }
108
109 static int
110 g_disk_access(struct g_provider *pp, int r, int w, int e)
111 {
112         struct disk *dp;
113         struct g_disk_softc *sc;
114         int error;
115
116         g_trace(G_T_ACCESS, "g_disk_access(%s, %d, %d, %d)",
117             pp->name, r, w, e);
118         g_topology_assert();
119         sc = pp->private;
120         if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
121                 /*
122                  * Allow decreasing access count even if disk is not
123                  * avaliable anymore.
124                  */
125                 if (r <= 0 && w <= 0 && e <= 0)
126                         return (0);
127                 return (ENXIO);
128         }
129         r += pp->acr;
130         w += pp->acw;
131         e += pp->ace;
132         error = 0;
133         if ((pp->acr + pp->acw + pp->ace) == 0 && (r + w + e) > 0) {
134                 if (dp->d_open != NULL) {
135                         g_disk_lock_giant(dp);
136                         error = dp->d_open(dp);
137                         if (bootverbose && error != 0)
138                                 printf("Opened disk %s -> %d\n",
139                                     pp->name, error);
140                         g_disk_unlock_giant(dp);
141                         if (error != 0)
142                                 return (error);
143                 }
144                 pp->mediasize = dp->d_mediasize;
145                 pp->sectorsize = dp->d_sectorsize;
146                 if (dp->d_maxsize == 0) {
147                         printf("WARNING: Disk drive %s%d has no d_maxsize\n",
148                             dp->d_name, dp->d_unit);
149                         dp->d_maxsize = DFLTPHYS;
150                 }
151                 if (dp->d_delmaxsize == 0) {
152                         if (bootverbose && dp->d_flags & DISKFLAG_CANDELETE) {
153                                 printf("WARNING: Disk drive %s%d has no "
154                                     "d_delmaxsize\n", dp->d_name, dp->d_unit);
155                         }
156                         dp->d_delmaxsize = dp->d_maxsize;
157                 }
158                 pp->stripeoffset = dp->d_stripeoffset;
159                 pp->stripesize = dp->d_stripesize;
160                 dp->d_flags |= DISKFLAG_OPEN;
161         } else if ((pp->acr + pp->acw + pp->ace) > 0 && (r + w + e) == 0) {
162                 if (dp->d_close != NULL) {
163                         g_disk_lock_giant(dp);
164                         error = dp->d_close(dp);
165                         if (error != 0)
166                                 printf("Closed disk %s -> %d\n",
167                                     pp->name, error);
168                         g_disk_unlock_giant(dp);
169                 }
170                 sc->state = G_STATE_ACTIVE;
171                 if (sc->led[0] != 0)
172                         led_set(sc->led, "0");
173                 dp->d_flags &= ~DISKFLAG_OPEN;
174         }
175         return (error);
176 }
177
178 static void
179 g_disk_kerneldump(struct bio *bp, struct disk *dp)
180 {
181         struct g_kerneldump *gkd;
182         struct g_geom *gp;
183
184         gkd = (struct g_kerneldump*)bp->bio_data;
185         gp = bp->bio_to->geom;
186         g_trace(G_T_TOPOLOGY, "g_disk_kerneldump(%s, %jd, %jd)",
187                 gp->name, (intmax_t)gkd->offset, (intmax_t)gkd->length);
188         if (dp->d_dump == NULL) {
189                 g_io_deliver(bp, ENODEV);
190                 return;
191         }
192         gkd->di.dumper = dp->d_dump;
193         gkd->di.priv = dp;
194         gkd->di.blocksize = dp->d_sectorsize;
195         gkd->di.maxiosize = dp->d_maxsize;
196         gkd->di.mediaoffset = gkd->offset;
197         if ((gkd->offset + gkd->length) > dp->d_mediasize)
198                 gkd->length = dp->d_mediasize - gkd->offset;
199         gkd->di.mediasize = gkd->length;
200         g_io_deliver(bp, 0);
201 }
202
203 static void
204 g_disk_setstate(struct bio *bp, struct g_disk_softc *sc)
205 {
206         const char *cmd;
207
208         memcpy(&sc->state, bp->bio_data, sizeof(sc->state));
209         if (sc->led[0] != 0) {
210                 switch (sc->state) {
211                 case G_STATE_FAILED:
212                         cmd = "1";
213                         break;
214                 case G_STATE_REBUILD:
215                         cmd = "f5";
216                         break;
217                 case G_STATE_RESYNC:
218                         cmd = "f1";
219                         break;
220                 default:
221                         cmd = "0";
222                         break;
223                 }
224                 led_set(sc->led, cmd);
225         }
226         g_io_deliver(bp, 0);
227 }
228
229 static void
230 g_disk_done(struct bio *bp)
231 {
232         struct bintime now;
233         struct bio *bp2;
234         struct g_disk_softc *sc;
235
236         /* See "notes" for why we need a mutex here */
237         /* XXX: will witness accept a mix of Giant/unGiant drivers here ? */
238         bp2 = bp->bio_parent;
239         sc = bp2->bio_to->private;
240         bp->bio_completed = bp->bio_length - bp->bio_resid;
241         binuptime(&now);
242         mtx_lock(&sc->done_mtx);
243         if (bp2->bio_error == 0)
244                 bp2->bio_error = bp->bio_error;
245         bp2->bio_completed += bp->bio_completed;
246         if ((bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE|BIO_FLUSH)) != 0)
247                 devstat_end_transaction_bio_bt(sc->dp->d_devstat, bp, &now);
248         bp2->bio_inbed++;
249         if (bp2->bio_children == bp2->bio_inbed) {
250                 mtx_unlock(&sc->done_mtx);
251                 bp2->bio_resid = bp2->bio_bcount - bp2->bio_completed;
252                 g_io_deliver(bp2, bp2->bio_error);
253         } else
254                 mtx_unlock(&sc->done_mtx);
255         g_destroy_bio(bp);
256 }
257
258 static int
259 g_disk_ioctl(struct g_provider *pp, u_long cmd, void * data, int fflag, struct thread *td)
260 {
261         struct disk *dp;
262         struct g_disk_softc *sc;
263         int error;
264
265         sc = pp->private;
266         dp = sc->dp;
267
268         if (dp->d_ioctl == NULL)
269                 return (ENOIOCTL);
270         g_disk_lock_giant(dp);
271         error = dp->d_ioctl(dp, cmd, data, fflag, td);
272         g_disk_unlock_giant(dp);
273         return (error);
274 }
275
276 static void
277 g_disk_start(struct bio *bp)
278 {
279         struct bio *bp2, *bp3;
280         struct disk *dp;
281         struct g_disk_softc *sc;
282         int error;
283         off_t off;
284
285         sc = bp->bio_to->private;
286         if (sc == NULL || (dp = sc->dp) == NULL || dp->d_destroyed) {
287                 g_io_deliver(bp, ENXIO);
288                 return;
289         }
290         error = EJUSTRETURN;
291         switch(bp->bio_cmd) {
292         case BIO_DELETE:
293                 if (!(dp->d_flags & DISKFLAG_CANDELETE)) {
294                         error = EOPNOTSUPP;
295                         break;
296                 }
297                 /* fall-through */
298         case BIO_READ:
299         case BIO_WRITE:
300                 off = 0;
301                 bp3 = NULL;
302                 bp2 = g_clone_bio(bp);
303                 if (bp2 == NULL) {
304                         error = ENOMEM;
305                         break;
306                 }
307                 do {
308                         off_t d_maxsize;
309
310                         d_maxsize = (bp->bio_cmd == BIO_DELETE) ?
311                             dp->d_delmaxsize : dp->d_maxsize;
312                         bp2->bio_offset += off;
313                         bp2->bio_length -= off;
314                         if ((bp->bio_flags & BIO_UNMAPPED) == 0) {
315                                 bp2->bio_data += off;
316                         } else {
317                                 KASSERT((dp->d_flags & DISKFLAG_UNMAPPED_BIO)
318                                     != 0,
319                                     ("unmapped bio not supported by disk %s",
320                                     dp->d_name));
321                                 bp2->bio_ma += off / PAGE_SIZE;
322                                 bp2->bio_ma_offset += off;
323                                 bp2->bio_ma_offset %= PAGE_SIZE;
324                                 bp2->bio_ma_n -= off / PAGE_SIZE;
325                         }
326                         if (bp2->bio_length > d_maxsize) {
327                                 /*
328                                  * XXX: If we have a stripesize we should really
329                                  * use it here. Care should be taken in the delete
330                                  * case if this is done as deletes can be very 
331                                  * sensitive to size given how they are processed.
332                                  */
333                                 bp2->bio_length = d_maxsize;
334                                 if ((bp->bio_flags & BIO_UNMAPPED) != 0) {
335                                         bp2->bio_ma_n = howmany(
336                                             bp2->bio_ma_offset +
337                                             bp2->bio_length, PAGE_SIZE);
338                                 }
339                                 off += d_maxsize;
340                                 /*
341                                  * To avoid a race, we need to grab the next bio
342                                  * before we schedule this one.  See "notes".
343                                  */
344                                 bp3 = g_clone_bio(bp);
345                                 if (bp3 == NULL)
346                                         bp->bio_error = ENOMEM;
347                         }
348                         bp2->bio_done = g_disk_done;
349                         bp2->bio_pblkno = bp2->bio_offset / dp->d_sectorsize;
350                         bp2->bio_bcount = bp2->bio_length;
351                         bp2->bio_disk = dp;
352                         mtx_lock(&sc->start_mtx); 
353                         devstat_start_transaction_bio(dp->d_devstat, bp2);
354                         mtx_unlock(&sc->start_mtx); 
355                         g_disk_lock_giant(dp);
356                         dp->d_strategy(bp2);
357                         g_disk_unlock_giant(dp);
358                         bp2 = bp3;
359                         bp3 = NULL;
360                 } while (bp2 != NULL);
361                 break;
362         case BIO_GETATTR:
363                 /* Give the driver a chance to override */
364                 if (dp->d_getattr != NULL) {
365                         if (bp->bio_disk == NULL)
366                                 bp->bio_disk = dp;
367                         error = dp->d_getattr(bp);
368                         if (error != -1)
369                                 break;
370                         error = EJUSTRETURN;
371                 }
372                 if (g_handleattr_int(bp, "GEOM::candelete",
373                     (dp->d_flags & DISKFLAG_CANDELETE) != 0))
374                         break;
375                 else if (g_handleattr_int(bp, "GEOM::fwsectors",
376                     dp->d_fwsectors))
377                         break;
378                 else if (g_handleattr_int(bp, "GEOM::fwheads", dp->d_fwheads))
379                         break;
380                 else if (g_handleattr_off_t(bp, "GEOM::frontstuff", 0))
381                         break;
382                 else if (g_handleattr_str(bp, "GEOM::ident", dp->d_ident))
383                         break;
384                 else if (g_handleattr_uint16_t(bp, "GEOM::hba_vendor",
385                     dp->d_hba_vendor))
386                         break;
387                 else if (g_handleattr_uint16_t(bp, "GEOM::hba_device",
388                     dp->d_hba_device))
389                         break;
390                 else if (g_handleattr_uint16_t(bp, "GEOM::hba_subvendor",
391                     dp->d_hba_subvendor))
392                         break;
393                 else if (g_handleattr_uint16_t(bp, "GEOM::hba_subdevice",
394                     dp->d_hba_subdevice))
395                         break;
396                 else if (!strcmp(bp->bio_attribute, "GEOM::kerneldump"))
397                         g_disk_kerneldump(bp, dp);
398                 else if (!strcmp(bp->bio_attribute, "GEOM::setstate"))
399                         g_disk_setstate(bp, sc);
400                 else if (!strcmp(bp->bio_attribute, "GEOM::rotation_rate")) {
401                         uint64_t v;
402
403                         if ((dp->d_flags & DISKFLAG_LACKS_ROTRATE) == 0)
404                                 v = dp->d_rotation_rate;
405                         else
406                                 v = 0; /* rate unknown */
407                         g_handleattr_uint16_t(bp, "GEOM::rotation_rate", v);
408                         break;
409                 } else 
410                         error = ENOIOCTL;
411                 break;
412         case BIO_FLUSH:
413                 g_trace(G_T_BIO, "g_disk_flushcache(%s)",
414                     bp->bio_to->name);
415                 if (!(dp->d_flags & DISKFLAG_CANFLUSHCACHE)) {
416                         error = EOPNOTSUPP;
417                         break;
418                 }
419                 bp2 = g_clone_bio(bp);
420                 if (bp2 == NULL) {
421                         g_io_deliver(bp, ENOMEM);
422                         return;
423                 }
424                 bp2->bio_done = g_disk_done;
425                 bp2->bio_disk = dp;
426                 mtx_lock(&sc->start_mtx);
427                 devstat_start_transaction_bio(dp->d_devstat, bp2);
428                 mtx_unlock(&sc->start_mtx);
429                 g_disk_lock_giant(dp);
430                 dp->d_strategy(bp2);
431                 g_disk_unlock_giant(dp);
432                 break;
433         default:
434                 error = EOPNOTSUPP;
435                 break;
436         }
437         if (error != EJUSTRETURN)
438                 g_io_deliver(bp, error);
439         return;
440 }
441
442 static void
443 g_disk_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
444 {
445         struct bio *bp;
446         struct disk *dp;
447         struct g_disk_softc *sc;
448         char *buf;
449         int res = 0;
450
451         sc = gp->softc;
452         if (sc == NULL || (dp = sc->dp) == NULL)
453                 return;
454         if (indent == NULL) {
455                 sbuf_printf(sb, " hd %u", dp->d_fwheads);
456                 sbuf_printf(sb, " sc %u", dp->d_fwsectors);
457                 return;
458         }
459         if (pp != NULL) {
460                 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n",
461                     indent, dp->d_fwheads);
462                 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n",
463                     indent, dp->d_fwsectors);
464                 if (dp->d_getattr != NULL) {
465                         buf = g_malloc(DISK_IDENT_SIZE, M_WAITOK);
466                         bp = g_alloc_bio();
467                         bp->bio_disk = dp;
468                         bp->bio_attribute = "GEOM::ident";
469                         bp->bio_length = DISK_IDENT_SIZE;
470                         bp->bio_data = buf;
471                         res = dp->d_getattr(bp);
472                         sbuf_printf(sb, "%s<ident>", indent);
473                         g_conf_printf_escaped(sb, "%s",
474                             res == 0 ? buf: dp->d_ident);
475                         sbuf_printf(sb, "</ident>\n");
476                         bp->bio_attribute = "GEOM::lunid";
477                         bp->bio_length = DISK_IDENT_SIZE;
478                         bp->bio_data = buf;
479                         if (dp->d_getattr(bp) == 0) {
480                                 sbuf_printf(sb, "%s<lunid>", indent);
481                                 g_conf_printf_escaped(sb, "%s", buf);
482                                 sbuf_printf(sb, "</lunid>\n");
483                         }
484                         bp->bio_attribute = "GEOM::lunname";
485                         bp->bio_length = DISK_IDENT_SIZE;
486                         bp->bio_data = buf;
487                         if (dp->d_getattr(bp) == 0) {
488                                 sbuf_printf(sb, "%s<lunname>", indent);
489                                 g_conf_printf_escaped(sb, "%s", buf);
490                                 sbuf_printf(sb, "</lunname>\n");
491                         }
492                         g_destroy_bio(bp);
493                         g_free(buf);
494                 } else {
495                         sbuf_printf(sb, "%s<ident>", indent);
496                         g_conf_printf_escaped(sb, "%s", dp->d_ident);
497                         sbuf_printf(sb, "</ident>\n");
498                 }
499                 sbuf_printf(sb, "%s<descr>", indent);
500                 g_conf_printf_escaped(sb, "%s", dp->d_descr);
501                 sbuf_printf(sb, "</descr>\n");
502         }
503 }
504
505 static void
506 g_disk_resize(void *ptr, int flag)
507 {
508         struct disk *dp;
509         struct g_geom *gp;
510         struct g_provider *pp;
511
512         if (flag == EV_CANCEL)
513                 return;
514         g_topology_assert();
515
516         dp = ptr;
517         gp = dp->d_geom;
518
519         if (dp->d_destroyed || gp == NULL)
520                 return;
521
522         LIST_FOREACH(pp, &gp->provider, provider) {
523                 if (pp->sectorsize != 0 &&
524                     pp->sectorsize != dp->d_sectorsize)
525                         g_wither_provider(pp, ENXIO);
526                 else
527                         g_resize_provider(pp, dp->d_mediasize);
528         }
529 }
530
531 static void
532 g_disk_create(void *arg, int flag)
533 {
534         struct g_geom *gp;
535         struct g_provider *pp;
536         struct disk *dp;
537         struct g_disk_softc *sc;
538         char tmpstr[80];
539
540         if (flag == EV_CANCEL)
541                 return;
542         g_topology_assert();
543         dp = arg;
544         sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
545         mtx_init(&sc->start_mtx, "g_disk_start", NULL, MTX_DEF);
546         mtx_init(&sc->done_mtx, "g_disk_done", NULL, MTX_DEF);
547         sc->dp = dp;
548         gp = g_new_geomf(&g_disk_class, "%s%d", dp->d_name, dp->d_unit);
549         gp->softc = sc;
550         pp = g_new_providerf(gp, "%s", gp->name);
551         devstat_remove_entry(pp->stat);
552         pp->stat = NULL;
553         dp->d_devstat->id = pp;
554         pp->mediasize = dp->d_mediasize;
555         pp->sectorsize = dp->d_sectorsize;
556         pp->stripeoffset = dp->d_stripeoffset;
557         pp->stripesize = dp->d_stripesize;
558         if ((dp->d_flags & DISKFLAG_UNMAPPED_BIO) != 0)
559                 pp->flags |= G_PF_ACCEPT_UNMAPPED;
560         if ((dp->d_flags & DISKFLAG_DIRECT_COMPLETION) != 0)
561                 pp->flags |= G_PF_DIRECT_SEND;
562         pp->flags |= G_PF_DIRECT_RECEIVE;
563         if (bootverbose)
564                 printf("GEOM: new disk %s\n", gp->name);
565         sysctl_ctx_init(&sc->sysctl_ctx);
566         snprintf(tmpstr, sizeof(tmpstr), "GEOM disk %s", gp->name);
567         sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
568                 SYSCTL_STATIC_CHILDREN(_kern_geom_disk), OID_AUTO, gp->name,
569                 CTLFLAG_RD, 0, tmpstr);
570         if (sc->sysctl_tree != NULL) {
571                 snprintf(tmpstr, sizeof(tmpstr),
572                     "kern.geom.disk.%s.led", gp->name);
573                 TUNABLE_STR_FETCH(tmpstr, sc->led, sizeof(sc->led));
574                 SYSCTL_ADD_STRING(&sc->sysctl_ctx,
575                     SYSCTL_CHILDREN(sc->sysctl_tree), OID_AUTO, "led",
576                     CTLFLAG_RW | CTLFLAG_TUN, sc->led, sizeof(sc->led),
577                     "LED name");
578         }
579         pp->private = sc;
580         dp->d_geom = gp;
581         g_error_provider(pp, 0);
582 }
583
584 /*
585  * We get this callback after all of the consumers have gone away, and just
586  * before the provider is freed.  If the disk driver provided a d_gone
587  * callback, let them know that it is okay to free resources -- they won't
588  * be getting any more accesses from GEOM.
589  */
590 static void
591 g_disk_providergone(struct g_provider *pp)
592 {
593         struct disk *dp;
594         struct g_disk_softc *sc;
595
596         sc = (struct g_disk_softc *)pp->private;
597         dp = sc->dp;
598         if (dp != NULL && dp->d_gone != NULL)
599                 dp->d_gone(dp);
600         if (sc->sysctl_tree != NULL) {
601                 sysctl_ctx_free(&sc->sysctl_ctx);
602                 sc->sysctl_tree = NULL;
603         }
604         if (sc->led[0] != 0) {
605                 led_set(sc->led, "0");
606                 sc->led[0] = 0;
607         }
608         pp->private = NULL;
609         pp->geom->softc = NULL;
610         mtx_destroy(&sc->done_mtx);
611         mtx_destroy(&sc->start_mtx);
612         g_free(sc);
613 }
614
615 static void
616 g_disk_destroy(void *ptr, int flag)
617 {
618         struct disk *dp;
619         struct g_geom *gp;
620         struct g_disk_softc *sc;
621
622         g_topology_assert();
623         dp = ptr;
624         gp = dp->d_geom;
625         if (gp != NULL) {
626                 sc = gp->softc;
627                 if (sc != NULL)
628                         sc->dp = NULL;
629                 dp->d_geom = NULL;
630                 g_wither_geom(gp, ENXIO);
631         }
632         g_free(dp);
633 }
634
635 /*
636  * We only allow printable characters in disk ident,
637  * the rest is converted to 'x<HH>'.
638  */
639 static void
640 g_disk_ident_adjust(char *ident, size_t size)
641 {
642         char *p, tmp[4], newid[DISK_IDENT_SIZE];
643
644         newid[0] = '\0';
645         for (p = ident; *p != '\0'; p++) {
646                 if (isprint(*p)) {
647                         tmp[0] = *p;
648                         tmp[1] = '\0';
649                 } else {
650                         snprintf(tmp, sizeof(tmp), "x%02hhx",
651                             *(unsigned char *)p);
652                 }
653                 if (strlcat(newid, tmp, sizeof(newid)) >= sizeof(newid))
654                         break;
655         }
656         bzero(ident, size);
657         strlcpy(ident, newid, size);
658 }
659
660 struct disk *
661 disk_alloc(void)
662 {
663
664         return (g_malloc(sizeof(struct disk), M_WAITOK | M_ZERO));
665 }
666
667 void
668 disk_create(struct disk *dp, int version)
669 {
670
671         if (version != DISK_VERSION) {
672                 printf("WARNING: Attempt to add disk %s%d %s",
673                     dp->d_name, dp->d_unit,
674                     " using incompatible ABI version of disk(9)\n");
675                 printf("WARNING: Ignoring disk %s%d\n",
676                     dp->d_name, dp->d_unit);
677                 return;
678         }
679         if (version < DISK_VERSION_04)
680                 dp->d_flags |= DISKFLAG_LACKS_ROTRATE;
681         KASSERT(dp->d_strategy != NULL, ("disk_create need d_strategy"));
682         KASSERT(dp->d_name != NULL, ("disk_create need d_name"));
683         KASSERT(*dp->d_name != 0, ("disk_create need d_name"));
684         KASSERT(strlen(dp->d_name) < SPECNAMELEN - 4, ("disk name too long"));
685         if (dp->d_devstat == NULL)
686                 dp->d_devstat = devstat_new_entry(dp->d_name, dp->d_unit,
687                     dp->d_sectorsize, DEVSTAT_ALL_SUPPORTED,
688                     DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX);
689         dp->d_geom = NULL;
690         g_disk_ident_adjust(dp->d_ident, sizeof(dp->d_ident));
691         g_post_event(g_disk_create, dp, M_WAITOK, dp, NULL);
692 }
693
694 void
695 disk_destroy(struct disk *dp)
696 {
697
698         g_cancel_event(dp);
699         dp->d_destroyed = 1;
700         if (dp->d_devstat != NULL)
701                 devstat_remove_entry(dp->d_devstat);
702         g_post_event(g_disk_destroy, dp, M_WAITOK, NULL);
703 }
704
705 void
706 disk_gone(struct disk *dp)
707 {
708         struct g_geom *gp;
709         struct g_provider *pp;
710
711         gp = dp->d_geom;
712         if (gp != NULL) {
713                 pp = LIST_FIRST(&gp->provider);
714                 if (pp != NULL) {
715                         KASSERT(LIST_NEXT(pp, provider) == NULL,
716                             ("geom %p has more than one provider", gp));
717                         g_wither_provider(pp, ENXIO);
718                 }
719         }
720 }
721
722 void
723 disk_attr_changed(struct disk *dp, const char *attr, int flag)
724 {
725         struct g_geom *gp;
726         struct g_provider *pp;
727
728         gp = dp->d_geom;
729         if (gp != NULL)
730                 LIST_FOREACH(pp, &gp->provider, provider)
731                         (void)g_attr_changed(pp, attr, flag);
732 }
733
734 void
735 disk_media_changed(struct disk *dp, int flag)
736 {
737         struct g_geom *gp;
738         struct g_provider *pp;
739
740         gp = dp->d_geom;
741         if (gp != NULL) {
742                 pp = LIST_FIRST(&gp->provider);
743                 if (pp != NULL) {
744                         KASSERT(LIST_NEXT(pp, provider) == NULL,
745                             ("geom %p has more than one provider", gp));
746                         g_media_changed(pp, flag);
747                 }
748         }
749 }
750
751 void
752 disk_media_gone(struct disk *dp, int flag)
753 {
754         struct g_geom *gp;
755         struct g_provider *pp;
756
757         gp = dp->d_geom;
758         if (gp != NULL) {
759                 pp = LIST_FIRST(&gp->provider);
760                 if (pp != NULL) {
761                         KASSERT(LIST_NEXT(pp, provider) == NULL,
762                             ("geom %p has more than one provider", gp));
763                         g_media_gone(pp, flag);
764                 }
765         }
766 }
767
768 int
769 disk_resize(struct disk *dp, int flag)
770 {
771
772         if (dp->d_destroyed || dp->d_geom == NULL)
773                 return (0);
774
775         return (g_post_event(g_disk_resize, dp, flag, NULL));
776 }
777
778 static void
779 g_kern_disks(void *p, int flag __unused)
780 {
781         struct sbuf *sb;
782         struct g_geom *gp;
783         char *sp;
784
785         sb = p;
786         sp = "";
787         g_topology_assert();
788         LIST_FOREACH(gp, &g_disk_class.geom, geom) {
789                 sbuf_printf(sb, "%s%s", sp, gp->name);
790                 sp = " ";
791         }
792         sbuf_finish(sb);
793 }
794
795 static int
796 sysctl_disks(SYSCTL_HANDLER_ARGS)
797 {
798         int error;
799         struct sbuf *sb;
800
801         sb = sbuf_new_auto();
802         g_waitfor_event(g_kern_disks, sb, M_WAITOK, NULL);
803         error = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1);
804         sbuf_delete(sb);
805         return error;
806 }
807  
808 SYSCTL_PROC(_kern, OID_AUTO, disks,
809     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
810     sysctl_disks, "A", "names of available disks");