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
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <dev/ips/ipsreg.h>
32 #include <dev/ips/ips.h>
33 #include <dev/ips/ips_disk.h>
36 static int ipsd_probe(device_t dev
);
37 static int ipsd_attach(device_t dev
);
38 static int ipsd_detach(device_t dev
);
40 static int ipsd_dump(void *arg
, void *virtual, vm_offset_t physical
,
41 off_t offset
, size_t length
);
42 static void ipsd_dump_map_sg(void *arg
, bus_dma_segment_t
*segs
, int nsegs
,
44 static void ipsd_dump_block_complete(ips_command_t
*command
);
46 static disk_open_t ipsd_open
;
47 static disk_close_t ipsd_close
;
48 static disk_strategy_t ipsd_strategy
;
50 static device_method_t ipsd_methods
[] = {
51 DEVMETHOD(device_probe
, ipsd_probe
),
52 DEVMETHOD(device_attach
, ipsd_attach
),
53 DEVMETHOD(device_detach
, ipsd_detach
),
57 static driver_t ipsd_driver
= {
60 sizeof(ipsdisk_softc_t
)
63 static devclass_t ipsd_devclass
;
64 DRIVER_MODULE(ipsd
, ips
, ipsd_driver
, ipsd_devclass
, 0, 0);
66 /* handle opening of disk device. It must set up all
67 information about the geometry and size of the disk */
68 static int ipsd_open(struct disk
*dp
)
70 ipsdisk_softc_t
*dsc
= dp
->d_drv1
;
72 dsc
->state
|= IPS_DEV_OPEN
;
73 DEVICE_PRINTF(2, dsc
->dev
, "I'm open\n");
77 static int ipsd_close(struct disk
*dp
)
79 ipsdisk_softc_t
*dsc
= dp
->d_drv1
;
80 dsc
->state
&= ~IPS_DEV_OPEN
;
81 DEVICE_PRINTF(2, dsc
->dev
, "I'm closed for the day\n");
85 /* ipsd_finish is called to clean up and return a completed IO request */
86 void ipsd_finish(struct bio
*iobuf
)
89 dsc
= iobuf
->bio_disk
->d_drv1
;
91 if (iobuf
->bio_flags
& BIO_ERROR
) {
93 dsc
= iobuf
->bio_disk
->d_drv1
;
94 device_printf(dsc
->dev
, "iobuf error %d\n", iobuf
->bio_error
);
99 ips_start_io_request(dsc
->sc
);
103 static void ipsd_strategy(struct bio
*iobuf
)
105 ipsdisk_softc_t
*dsc
;
107 dsc
= iobuf
->bio_disk
->d_drv1
;
108 DEVICE_PRINTF(8,dsc
->dev
,"in strategy\n");
109 iobuf
->bio_driver1
= (void *)(uintptr_t)dsc
->sc
->drives
[dsc
->disk_number
].drivenum
;
110 mtx_lock(&dsc
->sc
->queue_mtx
);
111 bioq_insert_tail(&dsc
->sc
->queue
, iobuf
);
112 ips_start_io_request(dsc
->sc
);
113 mtx_unlock(&dsc
->sc
->queue_mtx
);
116 static int ipsd_probe(device_t dev
)
118 DEVICE_PRINTF(2,dev
, "in probe\n");
119 device_set_desc(dev
, "Logical Drive");
123 static int ipsd_attach(device_t dev
)
126 ipsdisk_softc_t
*dsc
;
129 DEVICE_PRINTF(2,dev
, "in attach\n");
131 dsc
= (ipsdisk_softc_t
*)device_get_softc(dev
);
132 bzero(dsc
, sizeof(ipsdisk_softc_t
));
133 adapter
= device_get_parent(dev
);
135 dsc
->sc
= device_get_softc(adapter
);
136 dsc
->unit
= device_get_unit(dev
);
137 dsc
->disk_number
= (uintptr_t) device_get_ivars(dev
);
138 dsc
->ipsd_disk
= disk_alloc();
139 dsc
->ipsd_disk
->d_drv1
= dsc
;
140 dsc
->ipsd_disk
->d_name
= "ipsd";
141 dsc
->ipsd_disk
->d_maxsize
= IPS_MAX_IO_SIZE
;
142 dsc
->ipsd_disk
->d_open
= ipsd_open
;
143 dsc
->ipsd_disk
->d_close
= ipsd_close
;
144 dsc
->ipsd_disk
->d_strategy
= ipsd_strategy
;
145 dsc
->ipsd_disk
->d_dump
= ipsd_dump
;
147 totalsectors
= dsc
->sc
->drives
[dsc
->disk_number
].sector_count
;
148 if ((totalsectors
> 0x400000) &&
149 ((dsc
->sc
->adapter_info
.miscflags
& 0x8) == 0)) {
150 dsc
->ipsd_disk
->d_fwheads
= IPS_NORM_HEADS
;
151 dsc
->ipsd_disk
->d_fwsectors
= IPS_NORM_SECTORS
;
153 dsc
->ipsd_disk
->d_fwheads
= IPS_COMP_HEADS
;
154 dsc
->ipsd_disk
->d_fwsectors
= IPS_COMP_SECTORS
;
156 dsc
->ipsd_disk
->d_sectorsize
= IPS_BLKSIZE
;
157 dsc
->ipsd_disk
->d_mediasize
= (off_t
)totalsectors
* IPS_BLKSIZE
;
158 dsc
->ipsd_disk
->d_unit
= dsc
->unit
;
159 dsc
->ipsd_disk
->d_flags
= 0;
160 disk_create(dsc
->ipsd_disk
, DISK_VERSION
);
162 device_printf(dev
, "Logical Drive (%dMB)\n",
163 dsc
->sc
->drives
[dsc
->disk_number
].sector_count
>> 11);
167 static int ipsd_detach(device_t dev
)
169 ipsdisk_softc_t
*dsc
;
171 DEVICE_PRINTF(2, dev
,"in detach\n");
172 dsc
= (ipsdisk_softc_t
*)device_get_softc(dev
);
173 if(dsc
->state
& IPS_DEV_OPEN
)
175 disk_destroy(dsc
->ipsd_disk
);
180 ipsd_dump(void *arg
, void *virtual, vm_offset_t physical
, off_t offset
,
183 ipsdisk_softc_t
*dsc
;
185 ips_command_t
*command
;
186 ips_io_cmd
*command_struct
;
200 if (ips_get_free_cmd(sc
, &command
, 0) != 0) {
201 printf("ipsd: failed to get cmd for dump\n");
205 command
->data_dmatag
= sc
->sg_dmatag
;
206 command
->callback
= ipsd_dump_block_complete
;
208 command_struct
= (ips_io_cmd
*)command
->command_buffer
;
209 command_struct
->id
= command
->id
;
210 command_struct
->drivenum
= sc
->drives
[dsc
->disk_number
].drivenum
;
217 (length
> IPS_MAX_IO_SIZE
) ? IPS_MAX_IO_SIZE
: length
;
219 command_struct
->lba
= off
/ IPS_BLKSIZE
;
221 if (bus_dmamap_load(command
->data_dmatag
, command
->data_dmamap
,
222 va
, len
, ipsd_dump_map_sg
, command
, BUS_DMA_NOWAIT
) != 0) {
226 if (COMMAND_ERROR(command
)) {
233 va
= (uint8_t *)va
+ len
;
236 ips_insert_free_cmd(command
->sc
, command
);
241 ipsd_dump_map_sg(void *arg
, bus_dma_segment_t
*segs
, int nsegs
, int error
)
244 ips_command_t
*command
;
245 ips_sg_element_t
*sg_list
;
246 ips_io_cmd
*command_struct
;
249 command
= (ips_command_t
*)arg
;
254 printf("ipsd_dump_map_sg: error %d\n", error
);
255 ips_set_error(command
, error
);
259 command_struct
= (ips_io_cmd
*)command
->command_buffer
;
262 command_struct
->segnum
= nsegs
;
263 sg_list
= (ips_sg_element_t
*)((uint8_t *)
264 command
->command_buffer
+ IPS_COMMAND_LEN
);
265 for (i
= 0; i
< nsegs
; i
++) {
266 sg_list
[i
].addr
= segs
[i
].ds_addr
;
267 sg_list
[i
].len
= segs
[i
].ds_len
;
268 length
+= segs
[i
].ds_len
;
270 command_struct
->buffaddr
=
271 (uint32_t)command
->command_phys_addr
+ IPS_COMMAND_LEN
;
272 command_struct
->command
= IPS_SG_WRITE_CMD
;
274 command_struct
->buffaddr
= segs
[0].ds_addr
;
275 length
= segs
[0].ds_len
;
276 command_struct
->segnum
= 0;
277 command_struct
->command
= IPS_WRITE_CMD
;
280 length
= (length
+ IPS_BLKSIZE
- 1) / IPS_BLKSIZE
;
281 command_struct
->length
= length
;
282 bus_dmamap_sync(sc
->command_dmatag
, command
->command_dmamap
,
283 BUS_DMASYNC_PREWRITE
);
284 bus_dmamap_sync(command
->data_dmatag
, command
->data_dmamap
,
285 BUS_DMASYNC_PREWRITE
);
287 sc
->ips_issue_cmd(command
);
288 sc
->ips_poll_cmd(command
);
293 ipsd_dump_block_complete(ips_command_t
*command
)
296 if (COMMAND_ERROR(command
))
297 printf("ipsd_dump completion error= 0x%x\n",
298 command
->status
.value
);
300 bus_dmamap_sync(command
->data_dmatag
, command
->data_dmamap
,
301 BUS_DMASYNC_POSTWRITE
);
302 bus_dmamap_unload(command
->data_dmatag
, command
->data_dmamap
);