2 * Written by: David Jeffery
3 * Copyright (c) 2002 Adaptec Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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
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.13 2007/06/17 23:50:16 dillon Exp $
31 #include <sys/devicestat.h>
32 #include <dev/raid/ips/ips.h>
33 #include <dev/raid/ips/ips_disk.h>
35 #include <sys/dtype.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
);
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
,
49 static void ipsd_dump_block_complete(ips_command_t
*command
);
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
},
60 .d_close
= ipsd_close
,
61 .d_strategy
= ipsd_strategy
,
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
),
75 static driver_t ipsd_driver
= {
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
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
;
96 dsc
->state
|= IPS_DEV_OPEN
;
97 DEVICE_PRINTF(2, dsc
->dev
, "I'm open\n");
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");
112 /* ipsd_finish is called to clean up and return a completed IO request */
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
);
125 devstat_end_transaction_buf(&dsc
->stats
, bp
);
127 ips_start_io_request(dsc
->sc
);
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
;
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 bioq_insert_tail(&dsc
->sc
->bio_queue
, bio
);
144 ips_start_io_request(dsc
->sc
);
145 lockmgr(&dsc
->sc
->queue_lock
, LK_RELEASE
);
150 ipsd_probe(device_t dev
)
152 DEVICE_PRINTF(2, dev
, "in probe\n");
153 device_set_desc(dev
, "Logical Drive");
158 ipsd_attach(device_t dev
)
161 ipsdisk_softc_t
*dsc
;
162 struct disk_info info
;
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
);
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
;
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);
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
)
217 devstat_remove_entry(&dsc
->stats
);
218 disk_destroy(&dsc
->ipsd_disk
);
223 ipsd_dump_helper(struct dev_dump_args
*ap
)
225 kprintf("dump support for IPS not yet working, will not dump\n");
232 int dumppages
= MAXDUMPPGS
;
236 blkcnt
= howmany(PAGE_SIZE
, secsize
);
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
))
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)
251 blkno
+= blkcnt
* dumppages
;
252 count
-= blkcnt
* dumppages
;
253 addr
+= PAGE_SIZE
* dumppages
;
262 ipsd_dump(void *arg
, void *virtual, vm_offset_t physical
, off_t offset
,
267 ips_command_t
*command
;
268 ips_io_cmd
*command_struct
;
269 ipsdisk_softc_t
*dsc
;
280 if (ips_get_free_cmd(sc
, &command
, 0) != 0) {
281 kprintf("ipsd: failed to get cmd for dump\n");
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
;
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) {
303 if (COMMAND_ERROR(&command
->status
)) {
312 ips_insert_free_cmd(command
->sc
, command
);
317 ipsd_dump_map_sg(void *arg
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
320 ips_command_t
*command
;
321 ips_sg_element_t
*sg_list
;
322 ips_io_cmd
*command_struct
;
325 command
= (ips_command_t
*)arg
;
330 kprintf("ipsd_dump_map_sg: error %d\n", error
);
331 command
->status
.value
= IPS_ERROR_STATUS
;
335 command_struct
= (ips_io_cmd
*)command
->command_buffer
;
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
;
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
);
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
);