Merge commit 'crater/master'
[dragonfly.git] / sys / dev / raid / ips / ips_disk.c
blobda1d96f1dd544c083e60fc91f9a9911832b5c161
1 /*-
2 * Written by: David Jeffery
3 * Copyright (c) 2002 Adaptec Inc.
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
27 * $FreeBSD: src/sys/dev/ips/ips_disk.c,v 1.4 2003/09/22 04:59:07 njl Exp $
28 * $DragonFly: src/sys/dev/raid/ips/ips_disk.c,v 1.14 2008/06/10 17:20:52 dillon Exp $
31 #include <sys/devicestat.h>
32 #include <dev/raid/ips/ips.h>
33 #include <dev/raid/ips/ips_disk.h>
34 #include <sys/stat.h>
35 #include <sys/dtype.h>
37 #include <vm/vm.h>
38 #include <vm/pmap.h>
39 #include <machine/md_var.h>
41 static int ipsd_probe(device_t dev);
42 static int ipsd_attach(device_t dev);
43 static int ipsd_detach(device_t dev);
45 #if 0
46 static int ipsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t length);
47 static void ipsd_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs,
48 int error);
49 static void ipsd_dump_block_complete(ips_command_t *command);
50 #endif
52 static d_open_t ipsd_open;
53 static d_close_t ipsd_close;
54 static d_strategy_t ipsd_strategy;
55 static d_dump_t ipsd_dump_helper;
57 static struct dev_ops ipsd_ops = {
58 { "ipsd", IPSD_CDEV_MAJOR, D_DISK },
59 .d_open = ipsd_open,
60 .d_close = ipsd_close,
61 .d_strategy = ipsd_strategy,
62 .d_read = physread,
63 .d_write = physwrite,
64 .d_dump = ipsd_dump_helper,
67 static device_method_t ipsd_methods[] = {
68 DEVMETHOD(device_probe, ipsd_probe),
69 DEVMETHOD(device_attach, ipsd_attach),
70 DEVMETHOD(device_detach, ipsd_detach),
71 { 0, 0 }
75 static driver_t ipsd_driver = {
76 "ipsd",
77 ipsd_methods,
78 sizeof(ipsdisk_softc_t)
81 static devclass_t ipsd_devclass;
82 DRIVER_MODULE(ipsd, ips, ipsd_driver, ipsd_devclass, 0, 0);
85 * handle opening of disk device. It must set up all information about
86 * the geometry and size of the disk
88 static int
89 ipsd_open(struct dev_open_args *ap)
91 cdev_t dev = ap->a_head.a_dev;
92 ipsdisk_softc_t *dsc = dev->si_drv1;
94 if (dsc == NULL)
95 return (ENXIO);
96 dsc->state |= IPS_DEV_OPEN;
97 DEVICE_PRINTF(2, dsc->dev, "I'm open\n");
98 return 0;
101 static int
102 ipsd_close(struct dev_close_args *ap)
104 cdev_t dev = ap->a_head.a_dev;
105 ipsdisk_softc_t *dsc = dev->si_drv1;
107 dsc->state &= ~IPS_DEV_OPEN;
108 DEVICE_PRINTF(2, dsc->dev, "I'm closed for the day\n");
109 return 0;
112 /* ipsd_finish is called to clean up and return a completed IO request */
113 void
114 ipsd_finish(struct bio *bio)
116 struct buf *bp = bio->bio_buf;
117 ipsdisk_softc_t *dsc;
119 dsc = bio->bio_driver_info;
120 if (bp->b_flags & B_ERROR) {
121 device_printf(dsc->dev, "iobuf error %d\n", bp->b_error);
122 } else {
123 bp->b_resid = 0;
125 devstat_end_transaction_buf(&dsc->stats, bp);
126 biodone(bio);
127 ips_start_io_request(dsc->sc);
131 static int
132 ipsd_strategy(struct dev_strategy_args *ap)
134 cdev_t dev = ap->a_head.a_dev;
135 struct bio *bio = ap->a_bio;
136 ipsdisk_softc_t *dsc;
138 dsc = dev->si_drv1;
139 DEVICE_PRINTF(8, dsc->dev, "in strategy\n");
140 bio->bio_driver_info = dsc;
141 devstat_start_transaction(&dsc->stats);
142 lockmgr(&dsc->sc->queue_lock, LK_EXCLUSIVE|LK_RETRY);
143 bioqdisksort(&dsc->sc->bio_queue, bio);
144 ips_start_io_request(dsc->sc);
145 lockmgr(&dsc->sc->queue_lock, LK_RELEASE);
146 return(0);
149 static int
150 ipsd_probe(device_t dev)
152 DEVICE_PRINTF(2, dev, "in probe\n");
153 device_set_desc(dev, "Logical Drive");
154 return 0;
157 static int
158 ipsd_attach(device_t dev)
160 device_t adapter;
161 ipsdisk_softc_t *dsc;
162 struct disk_info info;
163 u_int totalsectors;
164 u_int nheads, nsectors;
166 DEVICE_PRINTF(2, dev, "in attach\n");
167 dsc = (ipsdisk_softc_t *)device_get_softc(dev);
168 bzero(dsc, sizeof(ipsdisk_softc_t));
169 adapter = device_get_parent(dev);
170 dsc->dev = dev;
171 dsc->sc = device_get_softc(adapter);
172 dsc->unit = device_get_unit(dev);
173 dsc->disk_number = (uintptr_t) device_get_ivars(dev);
174 totalsectors = dsc->sc->drives[dsc->disk_number].sector_count;
175 if ((totalsectors > 0x400000) &&
176 ((dsc->sc->adapter_info.miscflags & 0x8) == 0)) {
177 nheads = IPS_NORM_HEADS;
178 nsectors = IPS_NORM_SECTORS;
179 } else {
180 nheads = IPS_COMP_HEADS;
181 nsectors = IPS_COMP_SECTORS;
183 devstat_add_entry(&dsc->stats, "ipsd", dsc->unit, DEV_BSIZE,
184 DEVSTAT_NO_ORDERED_TAGS,
185 DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_SCSI,
186 DEVSTAT_PRIORITY_DISK);
187 dsc->ipsd_dev_t = disk_create(dsc->unit, &dsc->ipsd_disk, &ipsd_ops);
188 dsc->ipsd_dev_t->si_drv1 = dsc;
189 dsc->ipsd_dev_t->si_iosize_max = IPS_MAX_IO_SIZE;
191 bzero(&info, sizeof(info));
192 info.d_media_blksize = IPS_BLKSIZE; /* mandatory */
193 info.d_media_blocks = totalsectors;
195 info.d_type = DTYPE_ESDI; /* optional */
196 info.d_nheads = nheads;
197 info.d_secpertrack = nsectors;
198 info.d_ncylinders = totalsectors / nheads / nsectors;
199 info.d_secpercyl = nsectors / nheads;
201 disk_setdiskinfo(&dsc->ipsd_disk, &info);
203 device_printf(dev, "Logical Drive (%dMB)\n",
204 dsc->sc->drives[dsc->disk_number].sector_count >> 11);
205 return 0;
208 static int
209 ipsd_detach(device_t dev)
211 ipsdisk_softc_t *dsc;
213 DEVICE_PRINTF(2, dev, "in detach\n");
214 dsc = (ipsdisk_softc_t *)device_get_softc(dev);
215 if (dsc->state & IPS_DEV_OPEN)
216 return (EBUSY);
217 devstat_remove_entry(&dsc->stats);
218 disk_destroy(&dsc->ipsd_disk);
219 return 0;
222 static int
223 ipsd_dump_helper(struct dev_dump_args *ap)
225 kprintf("dump support for IPS not yet working, will not dump\n");
226 return (ENODEV);
228 #if 0
229 long blkcnt;
230 caddr_t va;
231 vm_offset_t addr, a;
232 int dumppages = MAXDUMPPGS;
233 int i;
235 addr = 0;
236 blkcnt = howmany(PAGE_SIZE, secsize);
237 while (count > 0) {
238 va = NULL;
239 if (count / blkcnt < dumppages)
240 dumppages = count / blkcnt;
241 for (i = 0; i < dumppages; i++) {
242 a = addr + (i * PAGE_SIZE);
243 if (!is_physical_memory(a))
244 a = 0;
245 va = pmap_kenter_temporary(trunc_page(a), i);
248 ipsd_dump(dev, va, 0, blkno, PAGE_SIZE * dumppages);
249 if (dumpstatus(addr, (off_t)count * DEV_BSIZE) < 0)
250 return (EINTR);
251 blkno += blkcnt * dumppages;
252 count -= blkcnt * dumppages;
253 addr += PAGE_SIZE * dumppages;
255 return (0);
256 #endif
259 #if 0
261 static int
262 ipsd_dump(void *arg, void *virtual, vm_offset_t physical, off_t offset,
263 size_t length)
265 cdev_t dev = arg;
266 ips_softc_t *sc;
267 ips_command_t *command;
268 ips_io_cmd *command_struct;
269 ipsdisk_softc_t *dsc;
270 off_t off;
271 uint8_t *va;
272 int len;
273 int error = 0;
275 dsc = dev->si_drv1;
276 if (dsc == NULL)
277 return (EINVAL);
278 sc = dsc->sc;
280 if (ips_get_free_cmd(sc, &command, 0) != 0) {
281 kprintf("ipsd: failed to get cmd for dump\n");
282 return (ENOMEM);
285 command->data_dmatag = sc->sg_dmatag;
286 command->callback = ipsd_dump_block_complete;
288 command_struct = (ips_io_cmd *)command->command_buffer;
289 command_struct->id = command->id;
290 command_struct->drivenum = sc->drives[dsc->disk_number].drivenum;
292 off = offset;
293 va = virtual;
295 while (length > 0) {
296 len = length > IPS_MAX_IO_SIZE ? IPS_MAX_IO_SIZE : length;
297 command_struct->lba = off / IPS_BLKSIZE;
298 if (bus_dmamap_load(command->data_dmatag, command->data_dmamap,
299 va, len, ipsd_dump_map_sg, command, 0) != 0) {
300 error = EIO;
301 break;
303 if (COMMAND_ERROR(&command->status)) {
304 error = EIO;
305 break;
308 length -= len;
309 off += len;
310 va += len;
312 ips_insert_free_cmd(command->sc, command);
313 return(error);
316 static void
317 ipsd_dump_map_sg(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
319 ips_softc_t *sc;
320 ips_command_t *command;
321 ips_sg_element_t *sg_list;
322 ips_io_cmd *command_struct;
323 int i, length;
325 command = (ips_command_t *)arg;
326 sc = command->sc;
327 length = 0;
329 if (error) {
330 kprintf("ipsd_dump_map_sg: error %d\n", error);
331 command->status.value = IPS_ERROR_STATUS;
332 return;
335 command_struct = (ips_io_cmd *)command->command_buffer;
337 if (nsegs != 1) {
338 command_struct->segnum = nsegs;
339 sg_list = (ips_sg_element_t *)((uint8_t *)
340 command->command_buffer + IPS_COMMAND_LEN);
341 for (i = 0; i < nsegs; i++) {
342 sg_list[i].addr = segs[i].ds_addr;
343 sg_list[i].len = segs[i].ds_len;
344 length += segs[i].ds_len;
346 command_struct->buffaddr =
347 (uint32_t)command->command_phys_addr + IPS_COMMAND_LEN;
348 command_struct->command = IPS_SG_WRITE_CMD;
349 } else {
350 command_struct->buffaddr = segs[0].ds_addr;
351 length = segs[0].ds_len;
352 command_struct->segnum = 0;
353 command_struct->command = IPS_WRITE_CMD;
356 length = (length + IPS_BLKSIZE - 1) / IPS_BLKSIZE;
357 command_struct->length = length;
358 bus_dmamap_sync(sc->command_dmatag, command->command_dmamap,
359 BUS_DMASYNC_PREWRITE);
360 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
361 BUS_DMASYNC_PREWRITE);
363 sc->ips_issue_cmd(command);
364 sc->ips_poll_cmd(command);
365 return;
368 static void
369 ipsd_dump_block_complete(ips_command_t *command)
371 if (COMMAND_ERROR(&command->status)) {
372 kprintf("ipsd_dump completion error= 0x%x\n",
373 command->status.value);
375 bus_dmamap_sync(command->data_dmatag, command->data_dmamap,
376 BUS_DMASYNC_POSTWRITE);
377 bus_dmamap_unload(command->data_dmatag, command->data_dmamap);
380 #endif