]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/aac/aac_disk.c
sysctl(9): Fix a few mandoc related issues
[FreeBSD/FreeBSD.git] / sys / dev / aac / aac_disk.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2000 Michael Smith
5  * Copyright (c) 2001 Scott Long
6  * Copyright (c) 2000 BSDi
7  * Copyright (c) 2001 Adaptec, Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include "opt_aac.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41
42 #include <sys/bus.h>
43 #include <sys/conf.h>
44 #include <sys/disk.h>
45
46 #include <vm/vm.h>
47 #include <vm/pmap.h>
48
49 #include <machine/md_var.h>
50 #include <machine/bus.h>
51 #include <sys/rman.h>
52
53 #include <dev/aac/aacreg.h>
54 #include <sys/aac_ioctl.h>
55 #include <dev/aac/aacvar.h>
56
57 /*
58  * Interface to parent.
59  */
60 static int aac_disk_probe(device_t dev);
61 static int aac_disk_attach(device_t dev);
62 static int aac_disk_detach(device_t dev);
63
64 /*
65  * Interface to the device switch.
66  */
67 static  disk_open_t     aac_disk_open;
68 static  disk_close_t    aac_disk_close;
69 static  disk_strategy_t aac_disk_strategy;
70 static  dumper_t        aac_disk_dump;
71
72 static devclass_t       aac_disk_devclass;
73
74 static device_method_t aac_disk_methods[] = {
75         DEVMETHOD(device_probe, aac_disk_probe),
76         DEVMETHOD(device_attach,        aac_disk_attach),
77         DEVMETHOD(device_detach,        aac_disk_detach),
78         DEVMETHOD_END
79 };
80
81 static driver_t aac_disk_driver = {
82         "aacd",
83         aac_disk_methods,
84         sizeof(struct aac_disk)
85 };
86
87 DRIVER_MODULE(aacd, aac, aac_disk_driver, aac_disk_devclass, NULL, NULL);
88
89 /*
90  * Handle open from generic layer.
91  *
92  * This is called by the diskslice code on first open in order to get the
93  * basic device geometry parameters.
94  */
95 static int
96 aac_disk_open(struct disk *dp)
97 {
98         struct aac_disk *sc;
99
100         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
101
102         sc = (struct aac_disk *)dp->d_drv1;
103
104         if (sc == NULL) {
105                 printf("aac_disk_open: No Softc\n");
106                 return (ENXIO);
107         }
108
109         /* check that the controller is up and running */
110         if (sc->ad_controller->aac_state & AAC_STATE_SUSPEND) {
111                 device_printf(sc->ad_controller->aac_dev,
112                     "Controller Suspended controller state = 0x%x\n",
113                     sc->ad_controller->aac_state);
114                 return(ENXIO);
115         }
116
117         sc->ad_flags |= AAC_DISK_OPEN;
118         return (0);
119 }
120
121 /*
122  * Handle last close of the disk device.
123  */
124 static int
125 aac_disk_close(struct disk *dp)
126 {
127         struct aac_disk *sc;
128
129         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
130
131         sc = (struct aac_disk *)dp->d_drv1;
132
133         if (sc == NULL)
134                 return (ENXIO);
135
136         sc->ad_flags &= ~AAC_DISK_OPEN;
137         return (0);
138 }
139
140 /*
141  * Handle an I/O request.
142  */
143 static void
144 aac_disk_strategy(struct bio *bp)
145 {
146         struct aac_disk *sc;
147
148         sc = (struct aac_disk *)bp->bio_disk->d_drv1;
149         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
150
151         /* bogus disk? */
152         if (sc == NULL) {
153                 bp->bio_flags |= BIO_ERROR;
154                 bp->bio_error = EINVAL;
155                 biodone(bp);
156                 return;
157         }
158
159         /* do-nothing operation? */
160         if (bp->bio_bcount == 0) {
161                 bp->bio_resid = bp->bio_bcount;
162                 biodone(bp);
163                 return;
164         }
165
166         if ((bp->bio_cmd != BIO_READ) && (bp->bio_cmd != BIO_WRITE)) {
167                 biofinish(bp, NULL, EOPNOTSUPP);
168                 return;
169         }
170
171         /* perform accounting */
172
173         /* pass the bio to the controller - it can work out who we are */
174         mtx_lock(&sc->ad_controller->aac_io_lock);
175         aac_submit_bio(bp);
176         mtx_unlock(&sc->ad_controller->aac_io_lock);
177 }
178
179 /*
180  * Map the S/G elements for doing a dump.
181  */
182 static void
183 aac_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
184 {
185         struct aac_fib *fib;
186         struct aac_blockwrite *bw;
187         struct aac_sg_table *sg;
188         int i;
189
190         fib = (struct aac_fib *)arg;
191         bw = (struct aac_blockwrite *)&fib->data[0];
192         sg = &bw->SgMap;
193
194         if (sg != NULL) {
195                 sg->SgCount = nsegs;
196                 for (i = 0; i < nsegs; i++) {
197                         if (segs[i].ds_addr >= BUS_SPACE_MAXADDR_32BIT)
198                                 return;
199                         sg->SgEntry[i].SgAddress = segs[i].ds_addr;
200                         sg->SgEntry[i].SgByteCount = segs[i].ds_len;
201                 }
202                 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry);
203         }
204 }
205
206 /*
207  * Map the S/G elements for doing a dump on 64-bit capable devices.
208  */
209 static void
210 aac_dump_map_sg64(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
211 {
212         struct aac_fib *fib;
213         struct aac_blockwrite64 *bw;
214         struct aac_sg_table64 *sg;
215         int i;
216
217         fib = (struct aac_fib *)arg;
218         bw = (struct aac_blockwrite64 *)&fib->data[0];
219         sg = &bw->SgMap64;
220
221         if (sg != NULL) {
222                 sg->SgCount = nsegs;
223                 for (i = 0; i < nsegs; i++) {
224                         sg->SgEntry64[i].SgAddress = segs[i].ds_addr;
225                         sg->SgEntry64[i].SgByteCount = segs[i].ds_len;
226                 }
227                 fib->Header.Size = nsegs * sizeof(struct aac_sg_entry64);
228         }
229 }
230
231 /*
232  * Dump memory out to an array
233  *
234  * Send out one command at a time with up to maxio of data.
235  */
236 static int
237 aac_disk_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length)
238 {
239         struct aac_disk *ad;
240         struct aac_softc *sc;
241         struct aac_fib *fib;
242         size_t len, maxio;
243         int size;
244         static bus_dmamap_t dump_datamap;
245         static int first = 0;
246         struct disk *dp;
247         bus_dmamap_callback_t *callback;
248         u_int32_t command;
249
250         dp = arg;
251         ad = dp->d_drv1;
252
253         if (ad == NULL)
254                 return (EINVAL);
255
256         sc= ad->ad_controller;
257
258         if (!first) {
259                 first = 1;
260                 if (bus_dmamap_create(sc->aac_buffer_dmat, 0, &dump_datamap)) {
261                         device_printf(sc->aac_dev,
262                             "bus_dmamap_create failed\n");
263                         return (ENOMEM);
264                 }
265         }
266
267         /* Skip aac_alloc_sync_fib().  We don't want to mess with sleep locks */
268         fib = &sc->aac_common->ac_sync_fib;
269
270         while (length > 0) {
271                 maxio = sc->aac_max_sectors << 9;
272                 len = (length > maxio) ? maxio : length;
273                 if ((sc->flags & AAC_FLAGS_SG_64BIT) == 0) {
274                         struct aac_blockwrite *bw;
275                         bw = (struct aac_blockwrite *)&fib->data[0];
276                         bw->Command = VM_CtBlockWrite;
277                         bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
278                         bw->BlockNumber = offset / AAC_BLOCK_SIZE;
279                         bw->ByteCount = len;
280                         bw->Stable = CUNSTABLE;
281                         command = ContainerCommand;
282                         callback = aac_dump_map_sg;
283                         size = sizeof(struct aac_blockwrite);
284                 } else {
285                         struct aac_blockwrite64 *bw;
286                         bw = (struct aac_blockwrite64 *)&fib->data[0];
287                         bw->Command = VM_CtHostWrite64;
288                         bw->ContainerId = ad->ad_container->co_mntobj.ObjectId;
289                         bw->BlockNumber = offset / AAC_BLOCK_SIZE;
290                         bw->SectorCount = len / AAC_BLOCK_SIZE;
291                         bw->Pad = 0;
292                         bw->Flags = 0;
293                         command = ContainerCommand64;
294                         callback = aac_dump_map_sg64;
295                         size = sizeof(struct aac_blockwrite64);
296                 }
297
298                 /*
299                  * There really isn't any way to recover from errors or
300                  * resource shortages here.  Oh well.  Because of that, don't
301                  * bother trying to send the command from the callback; there
302                  * is too much required context.
303                  */
304                 if (bus_dmamap_load(sc->aac_buffer_dmat, dump_datamap, virtual,
305                     len, callback, fib, BUS_DMA_NOWAIT) != 0)
306                         return (ENOMEM);
307
308                 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
309                     BUS_DMASYNC_PREWRITE);
310
311                 /* fib->Header.Size is set in aac_dump_map_sg */
312                 size += fib->Header.Size;
313
314                 if (aac_sync_fib(sc, command, 0, fib, size)) {
315                         device_printf(sc->aac_dev,
316                              "Error dumping block 0x%jx\n",
317                              (uintmax_t)physical);
318                         return (EIO);
319                 }
320
321                 bus_dmamap_sync(sc->aac_buffer_dmat, dump_datamap,
322                     BUS_DMASYNC_POSTWRITE);
323
324                 bus_dmamap_unload(sc->aac_buffer_dmat, dump_datamap);
325
326                 length -= len;
327                 offset += len;
328                 virtual = (uint8_t *)virtual + len;
329         }
330
331         return (0);
332 }
333
334 /*
335  * Handle completion of an I/O request.
336  */
337 void
338 aac_biodone(struct bio *bp)
339 {
340         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
341
342         if (bp->bio_flags & BIO_ERROR) {
343                 bp->bio_resid = bp->bio_bcount;
344                 disk_err(bp, "hard error", -1, 1);
345         }
346
347         biodone(bp);
348 }
349
350 /*
351  * Stub only.
352  */
353 static int
354 aac_disk_probe(device_t dev)
355 {
356
357         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
358
359         return (0);
360 }
361
362 /*
363  * Attach a unit to the controller.
364  */
365 static int
366 aac_disk_attach(device_t dev)
367 {
368         struct aac_disk *sc;
369
370         sc = (struct aac_disk *)device_get_softc(dev);
371         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
372
373         /* initialise our softc */
374         sc->ad_controller =
375             (struct aac_softc *)device_get_softc(device_get_parent(dev));
376         sc->ad_container = device_get_ivars(dev);
377         sc->ad_dev = dev;
378
379         /*
380          * require that extended translation be enabled - other drivers read the
381          * disk!
382          */
383         sc->ad_size = sc->ad_container->co_mntobj.Capacity;
384         if (sc->ad_controller->flags & AAC_FLAGS_LBA_64BIT)
385                 sc->ad_size += (u_int64_t)
386                         sc->ad_container->co_mntobj.CapacityHigh << 32;
387         if (sc->ad_size >= (2 * 1024 * 1024)) {         /* 2GB */
388                 sc->ad_heads = 255;
389                 sc->ad_sectors = 63;
390         } else if (sc->ad_size >= (1 * 1024 * 1024)) {  /* 1GB */
391                 sc->ad_heads = 128;
392                 sc->ad_sectors = 32;
393         } else {
394                 sc->ad_heads = 64;
395                 sc->ad_sectors = 32;
396         }
397         sc->ad_cylinders = (sc->ad_size / (sc->ad_heads * sc->ad_sectors));
398
399         device_printf(dev, "%juMB (%ju sectors)\n",
400                       (intmax_t)sc->ad_size / ((1024 * 1024) / AAC_BLOCK_SIZE),
401                       (intmax_t)sc->ad_size);
402
403         /* attach a generic disk device to ourselves */
404         sc->unit = device_get_unit(dev);
405         sc->ad_disk = disk_alloc();
406         sc->ad_disk->d_drv1 = sc;
407         sc->ad_disk->d_flags = DISKFLAG_UNMAPPED_BIO;
408         sc->ad_disk->d_name = "aacd";
409         sc->ad_disk->d_maxsize = sc->ad_controller->aac_max_sectors << 9;
410         sc->ad_disk->d_open = aac_disk_open;
411         sc->ad_disk->d_close = aac_disk_close;
412         sc->ad_disk->d_strategy = aac_disk_strategy;
413         sc->ad_disk->d_dump = aac_disk_dump;
414         sc->ad_disk->d_sectorsize = AAC_BLOCK_SIZE;
415         sc->ad_disk->d_mediasize = (off_t)sc->ad_size * AAC_BLOCK_SIZE;
416         sc->ad_disk->d_fwsectors = sc->ad_sectors;
417         sc->ad_disk->d_fwheads = sc->ad_heads;
418         sc->ad_disk->d_unit = sc->unit;
419         disk_create(sc->ad_disk, DISK_VERSION);
420
421         return (0);
422 }
423
424 /*
425  * Disconnect ourselves from the system.
426  */
427 static int
428 aac_disk_detach(device_t dev)
429 {
430         struct aac_disk *sc;
431
432         sc = (struct aac_disk *)device_get_softc(dev);
433         fwprintf(NULL, HBA_FLAGS_DBG_FUNCTION_ENTRY_B, "");
434
435         if (sc->ad_flags & AAC_DISK_OPEN)
436                 return(EBUSY);
437
438         disk_destroy(sc->ad_disk);
439
440         return(0);
441 }