1 /* $wasabi: ld_twa.c,v 1.9 2006/02/14 18:44:37 jordanr Exp $ */
2 /* $NetBSD: ld_twa.c,v 1.12 2008/08/11 06:43:38 simonb Exp $ */
5 * Copyright (c) 2000, 2001, 2002, 2003, 2004 The NetBSD Foundation, Inc.
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Andrew Doran, and by Jason R. Thorpe and Jordan Rhody of Wasabi
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
35 * 3ware "Apache" RAID controller front-end for ld(4) driver.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: ld_twa.c,v 1.12 2008/08/11 06:43:38 simonb Exp $");
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/kernel.h>
46 #include <sys/device.h>
49 #include <sys/endian.h>
59 #include <uvm/uvm_extern.h>
61 #include <dev/ldvar.h>
63 #include <dev/scsipi/scsipi_all.h>
64 #include <dev/scsipi/scsipi_disk.h>
65 #include <dev/scsipi/scsipiconf.h>
66 #include <dev/scsipi/scsi_disk.h>
69 #include <dev/pci/pcireg.h>
70 #include <dev/pci/pcivar.h>
71 #include <dev/pci/twareg.h>
72 #include <dev/pci/twavar.h>
75 struct ld_softc sc_ld
;
79 static void ld_twa_attach(device_t
, device_t
, void *);
80 static int ld_twa_detach(device_t
, int);
81 static int ld_twa_dobio(struct ld_twa_softc
*, void *, size_t, daddr_t
,
83 static int ld_twa_dump(struct ld_softc
*, void *, int, int);
84 static int ld_twa_flush(struct ld_softc
*, int);
85 static void ld_twa_handler(struct twa_request
*);
86 static int ld_twa_match(device_t
, cfdata_t
, void *);
87 static int ld_twa_start(struct ld_softc
*, struct buf
*);
89 static void ld_twa_adjqparam(device_t
, int);
91 static int ld_twa_scsicmd(struct ld_twa_softc
*,
92 struct twa_request
*, struct buf
*);
94 CFATTACH_DECL_NEW(ld_twa
, sizeof(struct ld_twa_softc
),
95 ld_twa_match
, ld_twa_attach
, ld_twa_detach
, NULL
);
97 static const struct twa_callbacks ld_twa_callbacks
= {
102 ld_twa_match(device_t parent
, cfdata_t match
, void *aux
)
109 ld_twa_attach(device_t parent
, device_t self
, void *aux
)
111 struct twa_attach_args
*twa_args
= aux
;
112 struct ld_twa_softc
*sc
= device_private(self
);
113 struct ld_softc
*ld
= &sc
->sc_ld
;
114 struct twa_softc
*twa
= device_private(parent
);
118 twa_register_callbacks(twa
, twa_args
->twaa_unit
, &ld_twa_callbacks
);
120 sc
->sc_hwunit
= twa_args
->twaa_unit
;
121 ld
->sc_maxxfer
= twa_get_maxxfer(twa_get_maxsegs());
122 ld
->sc_secperunit
= twa
->sc_units
[sc
->sc_hwunit
].td_size
;
123 ld
->sc_flags
= LDF_ENABLED
;
124 ld
->sc_secsize
= TWA_SECTOR_SIZE
;
125 ld
->sc_maxqueuecnt
= twa
->sc_units
[sc
->sc_hwunit
].td_openings
;
126 ld
->sc_start
= ld_twa_start
;
127 ld
->sc_dump
= ld_twa_dump
;
128 ld
->sc_flush
= ld_twa_flush
;
133 ld_twa_detach(device_t self
, int flags
)
135 struct ld_twa_softc
*sc
= device_private(self
);
136 struct ld_softc
*ld
= &sc
->sc_ld
;
139 if ((error
= ldbegindetach(ld
, flags
)) != 0)
147 ld_twa_dobio(struct ld_twa_softc
*sc
, void *data
, size_t datasize
,
148 daddr_t blkno
, struct buf
*bp
)
151 struct twa_request
*tr
;
152 struct twa_softc
*twa
;
154 twa
= device_private(device_parent(sc
->sc_ld
.sc_dv
));
156 if ((tr
= twa_get_request(twa
, 0)) == NULL
) {
159 if (bp
->b_flags
& B_READ
) {
160 tr
->tr_flags
= TWA_CMD_DATA_OUT
;
162 tr
->tr_flags
= TWA_CMD_DATA_IN
;
166 tr
->tr_length
= datasize
;
167 tr
->tr_cmd_pkt_type
=
168 (TWA_CMD_PKT_TYPE_9K
| TWA_CMD_PKT_TYPE_EXTERNAL
);
170 tr
->tr_command
->cmd_hdr
.header_desc
.size_header
= 128;
172 tr
->tr_command
->command
.cmd_pkt_9k
.command
.opcode
=
173 TWA_OP_EXECUTE_SCSI_COMMAND
;
174 tr
->tr_command
->command
.cmd_pkt_9k
.unit
=
176 tr
->tr_command
->command
.cmd_pkt_9k
.request_id
=
178 tr
->tr_command
->command
.cmd_pkt_9k
.status
= 0;
179 tr
->tr_command
->command
.cmd_pkt_9k
.sgl_entries
= 1;
180 tr
->tr_command
->command
.cmd_pkt_9k
.sgl_offset
= 16;
182 /* offset from end of hdr = max cdb len */
183 ld_twa_scsicmd(sc
, tr
, bp
);
185 tr
->tr_callback
= ld_twa_handler
;
190 rv
= twa_map_request(tr
);
196 ld_twa_start(struct ld_softc
*ld
, struct buf
*bp
)
199 return (ld_twa_dobio((struct ld_twa_softc
*)ld
, bp
->b_data
,
200 bp
->b_bcount
, bp
->b_rawblkno
, bp
));
204 ld_twa_handler(struct twa_request
*tr
)
208 struct ld_twa_softc
*sc
;
209 struct twa_softc
*twa
;
212 sc
= (struct ld_twa_softc
*)tr
->tr_ld_sc
;
213 twa
= device_private(device_parent(sc
->sc_ld
.sc_dv
));
215 status
= tr
->tr_command
->command
.cmd_pkt_9k
.status
;
219 bp
->b_resid
= bp
->b_bcount
;
224 twa_release_request(tr
);
226 lddone(&sc
->sc_ld
, bp
);
230 ld_twa_dump(struct ld_softc
*ld
, void *data
, int blkno
, int blkcnt
)
234 /* XXX Unsafe right now. */
235 return (ld_twa_dobio((struct ld_twa_softc
*)ld
, data
,
236 blkcnt
* ld
->sc_secsize
, blkno
, NULL
));
245 ld_twa_flush(struct ld_softc
*ld
, int flags
)
248 struct twa_request
*tr
;
249 struct twa_softc
*twa
= device_private(device_parent(ld
->sc_dv
));
250 struct ld_twa_softc
*sc
= (void *)ld
;
251 struct twa_command_generic
*generic_cmd
;
253 /* Get a request packet. */
254 tr
= twa_get_request_wait(twa
, 0);
257 tr
->tr_cmd_pkt_type
=
258 (TWA_CMD_PKT_TYPE_9K
| TWA_CMD_PKT_TYPE_EXTERNAL
);
260 tr
->tr_callback
= twa_request_wait_handler
;
263 tr
->tr_command
->cmd_hdr
.header_desc
.size_header
= 128;
265 generic_cmd
= &(tr
->tr_command
->command
.cmd_pkt_7k
.generic
);
266 generic_cmd
->opcode
= TWA_OP_FLUSH
;
267 generic_cmd
->size
= 2;
268 generic_cmd
->unit
= sc
->sc_hwunit
;
269 generic_cmd
->request_id
= tr
->tr_request_id
;
270 generic_cmd
->sgl_offset
= 0;
271 generic_cmd
->host_id
= 0;
272 generic_cmd
->status
= 0;
273 generic_cmd
->flags
= 0;
274 generic_cmd
->count
= 0;
275 rv
= twa_map_request(tr
);
277 while (tr
->tr_status
!= TWA_CMD_COMPLETE
)
278 if ((rv
= tsleep(tr
, PRIBIO
, "twaflush", 60 * hz
)) != 0)
280 twa_release_request(tr
);
287 ld_twa_adjqparam(device_t self
, int openings
)
289 struct ld_twa_softc
*sc
= device_private(self
);
290 struct ld_softc
*ld
= &sc
->sc_ld
;
292 ldadjqparam(ld
, openings
);
297 ld_twa_scsicmd(struct ld_twa_softc
*sc
,
298 struct twa_request
*tr
, struct buf
*bp
)
300 if (tr
->tr_flags
== TWA_CMD_DATA_IN
) {
301 tr
->tr_command
->command
.cmd_pkt_9k
.cdb
[0] = WRITE_16
;
303 tr
->tr_command
->command
.cmd_pkt_9k
.cdb
[0] = READ_16
;
305 tr
->tr_command
->command
.cmd_pkt_9k
.cdb
[1] =
306 (sc
->sc_hwunit
<< 5); /* lun for CDB */
308 _lto8b(htole64(bp
->b_rawblkno
),
309 &tr
->tr_command
->command
.cmd_pkt_9k
.cdb
[2]);
310 _lto4b(htole32((bp
->b_bcount
/ TWA_SECTOR_SIZE
)),
311 &tr
->tr_command
->command
.cmd_pkt_9k
.cdb
[10]);
313 tr
->tr_command
->command
.cmd_pkt_9k
.cdb
[14] = 0;
314 tr
->tr_command
->command
.cmd_pkt_9k
.cdb
[15] = 0;