Deleted Added
full compact
dpt_scsi.c (49860) dpt_scsi.c (50107)
1/*
2 * Copyright (c) 1997 by Simon Shapiro
3 * All Rights Reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions, and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
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.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * dpt_scsi.c: SCSI dependant code for the DPT driver
32 *
33 * credits: Assisted by Mike Neuffer in the early low level DPT code
34 * Thanx to Mark Salyzyn of DPT for his assistance.
35 * Special thanx to Justin Gibbs for invaluable help in
36 * making this driver look and work like a FreeBSD component.
37 * Last but not least, many thanx to UCB and the FreeBSD
38 * team for creating and maintaining such a wonderful O/S.
39 *
40 * TODO: * Add ISA probe code.
41 * * Add driver-level RAID-0. This will allow interoperability with
42 * NiceTry, M$-Doze, Win-Dog, Slowlaris, etc., in recognizing RAID
43 * arrays that span controllers (Wow!).
44 */
45
1/*
2 * Copyright (c) 1997 by Simon Shapiro
3 * All Rights Reserved
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions, and the following disclaimer,
10 * without modification, immediately at the beginning of the file.
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.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30/*
31 * dpt_scsi.c: SCSI dependant code for the DPT driver
32 *
33 * credits: Assisted by Mike Neuffer in the early low level DPT code
34 * Thanx to Mark Salyzyn of DPT for his assistance.
35 * Special thanx to Justin Gibbs for invaluable help in
36 * making this driver look and work like a FreeBSD component.
37 * Last but not least, many thanx to UCB and the FreeBSD
38 * team for creating and maintaining such a wonderful O/S.
39 *
40 * TODO: * Add ISA probe code.
41 * * Add driver-level RAID-0. This will allow interoperability with
42 * NiceTry, M$-Doze, Win-Dog, Slowlaris, etc., in recognizing RAID
43 * arrays that span controllers (Wow!).
44 */
45
46#ident "$Id: dpt_scsi.c,v 1.23 1999/05/06 20:16:22 ken Exp $"
46#ident "$Id: dpt_scsi.c,v 1.24 1999/08/16 01:49:35 gibbs Exp $"
47
48#define _DPT_C_
49
50#include "opt_dpt.h"
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/malloc.h>
54#include <sys/buf.h>
55#include <sys/kernel.h>
56
57#include <stddef.h> /* For offsetof */
58
59#include <machine/bus_memio.h>
60#include <machine/bus_pio.h>
61#include <machine/bus.h>
62#include <machine/clock.h>
63
64#include <cam/cam.h>
65#include <cam/cam_ccb.h>
66#include <cam/cam_sim.h>
67#include <cam/cam_xpt_sim.h>
68#include <cam/cam_debug.h>
69#include <cam/scsi/scsi_all.h>
70#include <cam/scsi/scsi_message.h>
71
72#include <vm/vm.h>
73#include <vm/pmap.h>
74
75#include <dev/dpt/dpt.h>
76
77/* dpt_isa.c, dpt_eisa.c, and dpt_pci.c need this in a central place */
78int dpt_controllers_present;
79
80u_long dpt_unit; /* Next unit number to use */
81
82/* The linked list of softc structures */
83struct dpt_softc_list dpt_softcs = TAILQ_HEAD_INITIALIZER(dpt_softcs);
84
85#define microtime_now dpt_time_now()
86
87#define dpt_inl(dpt, port) \
88 bus_space_read_4((dpt)->tag, (dpt)->bsh, port)
89#define dpt_inb(dpt, port) \
90 bus_space_read_1((dpt)->tag, (dpt)->bsh, port)
91#define dpt_outl(dpt, port, value) \
92 bus_space_write_4((dpt)->tag, (dpt)->bsh, port, value)
93#define dpt_outb(dpt, port, value) \
94 bus_space_write_1((dpt)->tag, (dpt)->bsh, port, value)
95
96/*
97 * These will have to be setup by parameters passed at boot/load time. For
98 * perfromance reasons, we make them constants for the time being.
99 */
100#define dpt_min_segs DPT_MAX_SEGS
101#define dpt_max_segs DPT_MAX_SEGS
102
103/* Definitions for our use of the SIM private CCB area */
104#define ccb_dccb_ptr spriv_ptr0
105#define ccb_dpt_ptr spriv_ptr1
106
107/* ================= Private Inline Function declarations ===================*/
108static __inline int dpt_just_reset(dpt_softc_t * dpt);
109static __inline int dpt_raid_busy(dpt_softc_t * dpt);
110static __inline int dpt_wait(dpt_softc_t *dpt, u_int bits,
111 u_int state);
112static __inline struct dpt_ccb* dptgetccb(struct dpt_softc *dpt);
113static __inline void dptfreeccb(struct dpt_softc *dpt,
114 struct dpt_ccb *dccb);
115static __inline u_int32_t dptccbvtop(struct dpt_softc *dpt,
116 struct dpt_ccb *dccb);
117
118static __inline int dpt_send_immediate(dpt_softc_t *dpt,
119 eata_ccb_t *cmd_block,
120 u_int32_t cmd_busaddr,
121 u_int retries,
122 u_int ifc, u_int code,
123 u_int code2);
124
125/* ==================== Private Function declarations =======================*/
126static void dptmapmem(void *arg, bus_dma_segment_t *segs,
127 int nseg, int error);
128
129static struct sg_map_node*
130 dptallocsgmap(struct dpt_softc *dpt);
131
132static int dptallocccbs(dpt_softc_t *dpt);
133
134static int dpt_get_conf(dpt_softc_t *dpt, dpt_ccb_t *dccb,
135 u_int32_t dccb_busaddr, u_int size,
136 u_int page, u_int target, int extent);
137static void dpt_detect_cache(dpt_softc_t *dpt, dpt_ccb_t *dccb,
138 u_int32_t dccb_busaddr,
139 u_int8_t *buff);
140
141static void dpt_poll(struct cam_sim *sim);
142
143static void dptexecuteccb(void *arg, bus_dma_segment_t *dm_segs,
144 int nseg, int error);
145
146static void dpt_action(struct cam_sim *sim, union ccb *ccb);
147
148static int dpt_send_eata_command(dpt_softc_t *dpt, eata_ccb_t *cmd,
149 u_int32_t cmd_busaddr,
150 u_int command, u_int retries,
151 u_int ifc, u_int code,
152 u_int code2);
153static void dptprocesserror(dpt_softc_t *dpt, dpt_ccb_t *dccb,
154 union ccb *ccb, u_int hba_stat,
155 u_int scsi_stat, u_int32_t resid);
156
157static void dpttimeout(void *arg);
47
48#define _DPT_C_
49
50#include "opt_dpt.h"
51#include <sys/param.h>
52#include <sys/systm.h>
53#include <sys/malloc.h>
54#include <sys/buf.h>
55#include <sys/kernel.h>
56
57#include <stddef.h> /* For offsetof */
58
59#include <machine/bus_memio.h>
60#include <machine/bus_pio.h>
61#include <machine/bus.h>
62#include <machine/clock.h>
63
64#include <cam/cam.h>
65#include <cam/cam_ccb.h>
66#include <cam/cam_sim.h>
67#include <cam/cam_xpt_sim.h>
68#include <cam/cam_debug.h>
69#include <cam/scsi/scsi_all.h>
70#include <cam/scsi/scsi_message.h>
71
72#include <vm/vm.h>
73#include <vm/pmap.h>
74
75#include <dev/dpt/dpt.h>
76
77/* dpt_isa.c, dpt_eisa.c, and dpt_pci.c need this in a central place */
78int dpt_controllers_present;
79
80u_long dpt_unit; /* Next unit number to use */
81
82/* The linked list of softc structures */
83struct dpt_softc_list dpt_softcs = TAILQ_HEAD_INITIALIZER(dpt_softcs);
84
85#define microtime_now dpt_time_now()
86
87#define dpt_inl(dpt, port) \
88 bus_space_read_4((dpt)->tag, (dpt)->bsh, port)
89#define dpt_inb(dpt, port) \
90 bus_space_read_1((dpt)->tag, (dpt)->bsh, port)
91#define dpt_outl(dpt, port, value) \
92 bus_space_write_4((dpt)->tag, (dpt)->bsh, port, value)
93#define dpt_outb(dpt, port, value) \
94 bus_space_write_1((dpt)->tag, (dpt)->bsh, port, value)
95
96/*
97 * These will have to be setup by parameters passed at boot/load time. For
98 * perfromance reasons, we make them constants for the time being.
99 */
100#define dpt_min_segs DPT_MAX_SEGS
101#define dpt_max_segs DPT_MAX_SEGS
102
103/* Definitions for our use of the SIM private CCB area */
104#define ccb_dccb_ptr spriv_ptr0
105#define ccb_dpt_ptr spriv_ptr1
106
107/* ================= Private Inline Function declarations ===================*/
108static __inline int dpt_just_reset(dpt_softc_t * dpt);
109static __inline int dpt_raid_busy(dpt_softc_t * dpt);
110static __inline int dpt_wait(dpt_softc_t *dpt, u_int bits,
111 u_int state);
112static __inline struct dpt_ccb* dptgetccb(struct dpt_softc *dpt);
113static __inline void dptfreeccb(struct dpt_softc *dpt,
114 struct dpt_ccb *dccb);
115static __inline u_int32_t dptccbvtop(struct dpt_softc *dpt,
116 struct dpt_ccb *dccb);
117
118static __inline int dpt_send_immediate(dpt_softc_t *dpt,
119 eata_ccb_t *cmd_block,
120 u_int32_t cmd_busaddr,
121 u_int retries,
122 u_int ifc, u_int code,
123 u_int code2);
124
125/* ==================== Private Function declarations =======================*/
126static void dptmapmem(void *arg, bus_dma_segment_t *segs,
127 int nseg, int error);
128
129static struct sg_map_node*
130 dptallocsgmap(struct dpt_softc *dpt);
131
132static int dptallocccbs(dpt_softc_t *dpt);
133
134static int dpt_get_conf(dpt_softc_t *dpt, dpt_ccb_t *dccb,
135 u_int32_t dccb_busaddr, u_int size,
136 u_int page, u_int target, int extent);
137static void dpt_detect_cache(dpt_softc_t *dpt, dpt_ccb_t *dccb,
138 u_int32_t dccb_busaddr,
139 u_int8_t *buff);
140
141static void dpt_poll(struct cam_sim *sim);
142
143static void dptexecuteccb(void *arg, bus_dma_segment_t *dm_segs,
144 int nseg, int error);
145
146static void dpt_action(struct cam_sim *sim, union ccb *ccb);
147
148static int dpt_send_eata_command(dpt_softc_t *dpt, eata_ccb_t *cmd,
149 u_int32_t cmd_busaddr,
150 u_int command, u_int retries,
151 u_int ifc, u_int code,
152 u_int code2);
153static void dptprocesserror(dpt_softc_t *dpt, dpt_ccb_t *dccb,
154 union ccb *ccb, u_int hba_stat,
155 u_int scsi_stat, u_int32_t resid);
156
157static void dpttimeout(void *arg);
158static void dptshutdown(int howto, void *arg);
158static void dptshutdown(void *arg, int howto);
159
160/* ================= Private Inline Function definitions ====================*/
161static __inline int
162dpt_just_reset(dpt_softc_t * dpt)
163{
164 if ((dpt_inb(dpt, 2) == 'D')
165 && (dpt_inb(dpt, 3) == 'P')
166 && (dpt_inb(dpt, 4) == 'T')
167 && (dpt_inb(dpt, 5) == 'H'))
168 return (1);
169 else
170 return (0);
171}
172
173static __inline int
174dpt_raid_busy(dpt_softc_t * dpt)
175{
176 if ((dpt_inb(dpt, 0) == 'D')
177 && (dpt_inb(dpt, 1) == 'P')
178 && (dpt_inb(dpt, 2) == 'T'))
179 return (1);
180 else
181 return (0);
182}
183
184static __inline int
185dpt_wait(dpt_softc_t *dpt, u_int bits, u_int state)
186{
187 int i;
188 u_int c;
189
190 for (i = 0; i < 20000; i++) { /* wait 20ms for not busy */
191 c = dpt_inb(dpt, HA_RSTATUS) & bits;
192 if (c == state)
193 return (0);
194 else
195 DELAY(50);
196 }
197 return (-1);
198}
199
200static __inline struct dpt_ccb*
201dptgetccb(struct dpt_softc *dpt)
202{
203 struct dpt_ccb* dccb;
204 int s;
205
206 s = splcam();
207 if ((dccb = SLIST_FIRST(&dpt->free_dccb_list)) != NULL) {
208 SLIST_REMOVE_HEAD(&dpt->free_dccb_list, links);
209 dpt->free_dccbs--;
210 } else if (dpt->total_dccbs < dpt->max_dccbs) {
211 dptallocccbs(dpt);
212 dccb = SLIST_FIRST(&dpt->free_dccb_list);
213 if (dccb == NULL)
214 printf("dpt%d: Can't malloc DCCB\n", dpt->unit);
215 else {
216 SLIST_REMOVE_HEAD(&dpt->free_dccb_list, links);
217 dpt->free_dccbs--;
218 }
219 }
220 splx(s);
221
222 return (dccb);
223}
224
225static __inline void
226dptfreeccb(struct dpt_softc *dpt, struct dpt_ccb *dccb)
227{
228 int s;
229
230 s = splcam();
231 if ((dccb->state & DCCB_ACTIVE) != 0)
232 LIST_REMOVE(&dccb->ccb->ccb_h, sim_links.le);
233 if ((dccb->state & DCCB_RELEASE_SIMQ) != 0)
234 dccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
235 else if (dpt->resource_shortage != 0
236 && (dccb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
237 dccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
238 dpt->resource_shortage = FALSE;
239 }
240 dccb->state = DCCB_FREE;
241 SLIST_INSERT_HEAD(&dpt->free_dccb_list, dccb, links);
242 ++dpt->free_dccbs;
243 splx(s);
244}
245
246static __inline u_int32_t
247dptccbvtop(struct dpt_softc *dpt, struct dpt_ccb *dccb)
248{
249 return (dpt->dpt_ccb_busbase
250 + (u_int32_t)((caddr_t)dccb - (caddr_t)dpt->dpt_dccbs));
251}
252
253static __inline struct dpt_ccb *
254dptccbptov(struct dpt_softc *dpt, u_int32_t busaddr)
255{
256 return (dpt->dpt_dccbs
257 + ((struct dpt_ccb *)busaddr
258 - (struct dpt_ccb *)dpt->dpt_ccb_busbase));
259}
260
261/*
262 * Send a command for immediate execution by the DPT
263 * See above function for IMPORTANT notes.
264 */
265static __inline int
266dpt_send_immediate(dpt_softc_t *dpt, eata_ccb_t *cmd_block,
267 u_int32_t cmd_busaddr, u_int retries,
268 u_int ifc, u_int code, u_int code2)
269{
270 return (dpt_send_eata_command(dpt, cmd_block, cmd_busaddr,
271 EATA_CMD_IMMEDIATE, retries, ifc,
272 code, code2));
273}
274
275
276/* ===================== Private Function definitions =======================*/
277static void
278dptmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
279{
280 bus_addr_t *busaddrp;
281
282 busaddrp = (bus_addr_t *)arg;
283 *busaddrp = segs->ds_addr;
284}
285
286static struct sg_map_node *
287dptallocsgmap(struct dpt_softc *dpt)
288{
289 struct sg_map_node *sg_map;
290
291 sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
292
293 if (sg_map == NULL)
294 return (NULL);
295
296 /* Allocate S/G space for the next batch of CCBS */
297 if (bus_dmamem_alloc(dpt->sg_dmat, (void **)&sg_map->sg_vaddr,
298 BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
299 free(sg_map, M_DEVBUF);
300 return (NULL);
301 }
302
303 (void)bus_dmamap_load(dpt->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
304 PAGE_SIZE, dptmapmem, &sg_map->sg_physaddr,
305 /*flags*/0);
306
307 SLIST_INSERT_HEAD(&dpt->sg_maps, sg_map, links);
308
309 return (sg_map);
310}
311
312/*
313 * Allocate another chunk of CCB's. Return count of entries added.
314 * Assumed to be called at splcam().
315 */
316static int
317dptallocccbs(dpt_softc_t *dpt)
318{
319 struct dpt_ccb *next_ccb;
320 struct sg_map_node *sg_map;
321 bus_addr_t physaddr;
322 dpt_sg_t *segs;
323 int newcount;
324 int i;
325
326 next_ccb = &dpt->dpt_dccbs[dpt->total_dccbs];
327
328 if (next_ccb == dpt->dpt_dccbs) {
329 /*
330 * First time through. Re-use the S/G
331 * space we allocated for initialization
332 * CCBS.
333 */
334 sg_map = SLIST_FIRST(&dpt->sg_maps);
335 } else {
336 sg_map = dptallocsgmap(dpt);
337 }
338
339 if (sg_map == NULL)
340 return (0);
341
342 segs = sg_map->sg_vaddr;
343 physaddr = sg_map->sg_physaddr;
344
345 newcount = (PAGE_SIZE / (dpt->sgsize * sizeof(dpt_sg_t)));
346 for (i = 0; dpt->total_dccbs < dpt->max_dccbs && i < newcount; i++) {
347 int error;
348
349 error = bus_dmamap_create(dpt->buffer_dmat, /*flags*/0,
350 &next_ccb->dmamap);
351 if (error != 0)
352 break;
353 next_ccb->sg_list = segs;
354 next_ccb->sg_busaddr = htonl(physaddr);
355 next_ccb->eata_ccb.cp_dataDMA = htonl(physaddr);
356 next_ccb->eata_ccb.cp_statDMA = htonl(dpt->sp_physaddr);
357 next_ccb->eata_ccb.cp_reqDMA =
358 htonl(dptccbvtop(dpt, next_ccb)
359 + offsetof(struct dpt_ccb, sense_data));
360 next_ccb->eata_ccb.cp_busaddr = dpt->dpt_ccb_busend;
361 next_ccb->state = DCCB_FREE;
362 next_ccb->tag = dpt->total_dccbs;
363 SLIST_INSERT_HEAD(&dpt->free_dccb_list, next_ccb, links);
364 segs += dpt->sgsize;
365 physaddr += (dpt->sgsize * sizeof(dpt_sg_t));
366 dpt->dpt_ccb_busend += sizeof(*next_ccb);
367 next_ccb++;
368 dpt->total_dccbs++;
369 }
370 return (i);
371}
372
373/*
374 * Read a configuration page into the supplied dpt_cont_t buffer.
375 */
376static int
377dpt_get_conf(dpt_softc_t *dpt, dpt_ccb_t *dccb, u_int32_t dccb_busaddr,
378 u_int size, u_int page, u_int target, int extent)
379{
380 eata_ccb_t *cp;
381
382 u_int8_t status;
383
384 int ndx;
385 int ospl;
386 int result;
387
388 cp = &dccb->eata_ccb;
389 bzero((void *)dpt->sp, sizeof(*dpt->sp));
390
391 cp->Interpret = 1;
392 cp->DataIn = 1;
393 cp->Auto_Req_Sen = 1;
394 cp->reqlen = sizeof(struct scsi_sense_data);
395
396 cp->cp_id = target;
397 cp->cp_LUN = 0; /* In the EATA packet */
398 cp->cp_lun = 0; /* In the SCSI command */
399
400 cp->cp_scsi_cmd = INQUIRY;
401 cp->cp_len = size;
402
403 cp->cp_extent = extent;
404
405 cp->cp_page = page;
406 cp->cp_channel = 0; /* DNC, Interpret mode is set */
407 cp->cp_identify = 1;
408 cp->cp_datalen = htonl(size);
409
410 ospl = splcam();
411
412 /*
413 * This could be a simple for loop, but we suspected the compiler To
414 * have optimized it a bit too much. Wait for the controller to
415 * become ready
416 */
417 while (((status = dpt_inb(dpt, HA_RSTATUS)) != (HA_SREADY | HA_SSC)
418 && (status != (HA_SREADY | HA_SSC | HA_SERROR))
419 && (status != (HA_SDRDY | HA_SERROR | HA_SDRQ)))
420 || (dpt_wait(dpt, HA_SBUSY, 0))) {
421
422 /*
423 * RAID Drives still Spinning up? (This should only occur if
424 * the DPT controller is in a NON PC (PCI?) platform).
425 */
426 if (dpt_raid_busy(dpt)) {
427 printf("dpt%d WARNING: Get_conf() RSUS failed.\n",
428 dpt->unit);
429 splx(ospl);
430 return (0);
431 }
432 }
433
434 DptStat_Reset_BUSY(dpt->sp);
435
436 /*
437 * XXXX We might want to do something more clever than aborting at
438 * this point, like resetting (rebooting) the controller and trying
439 * again.
440 */
441 if ((result = dpt_send_eata_command(dpt, cp, dccb_busaddr,
442 EATA_CMD_DMA_SEND_CP,
443 10000, 0, 0, 0)) != 0) {
444 printf("dpt%d WARNING: Get_conf() failed (%d) to send "
445 "EATA_CMD_DMA_READ_CONFIG\n",
446 dpt->unit, result);
447 splx(ospl);
448 return (0);
449 }
450 /* Wait for two seconds for a response. This can be slow */
451 for (ndx = 0;
452 (ndx < 20000)
453 && !((status = dpt_inb(dpt, HA_RAUXSTAT)) & HA_AIRQ);
454 ndx++) {
455 DELAY(50);
456 }
457
458 /* Grab the status and clear interrupts */
459 status = dpt_inb(dpt, HA_RSTATUS);
460
461 splx(ospl);
462
463 /*
464 * Check the status carefully. Return only if the
465 * command was successful.
466 */
467 if (((status & HA_SERROR) == 0)
468 && (dpt->sp->hba_stat == 0)
469 && (dpt->sp->scsi_stat == 0)
470 && (dpt->sp->residue_len == 0))
471 return (0);
472 return (1);
473}
474
475/* Detect Cache parameters and size */
476static void
477dpt_detect_cache(dpt_softc_t *dpt, dpt_ccb_t *dccb, u_int32_t dccb_busaddr,
478 u_int8_t *buff)
479{
480 eata_ccb_t *cp;
481 u_int8_t *param;
482 int bytes;
483 int result;
484 int ospl;
485 int ndx;
486 u_int8_t status;
487
488 /*
489 * Default setting, for best perfromance..
490 * This is what virtually all cards default to..
491 */
492 dpt->cache_type = DPT_CACHE_WRITEBACK;
493 dpt->cache_size = 0;
494
495 cp = &dccb->eata_ccb;
496 bzero((void *)dpt->sp, sizeof(dpt->sp));
497 bzero(buff, 512);
498
499 /* Setup the command structure */
500 cp->Interpret = 1;
501 cp->DataIn = 1;
502 cp->Auto_Req_Sen = 1;
503 cp->reqlen = sizeof(struct scsi_sense_data);
504
505 cp->cp_id = 0; /* who cares? The HBA will interpret.. */
506 cp->cp_LUN = 0; /* In the EATA packet */
507 cp->cp_lun = 0; /* In the SCSI command */
508 cp->cp_channel = 0;
509
510 cp->cp_scsi_cmd = EATA_CMD_DMA_SEND_CP;
511 cp->cp_len = 56;
512
513 cp->cp_extent = 0;
514 cp->cp_page = 0;
515 cp->cp_identify = 1;
516 cp->cp_dispri = 1;
517
518 /*
519 * Build the EATA Command Packet structure
520 * for a Log Sense Command.
521 */
522 cp->cp_cdb[0] = 0x4d;
523 cp->cp_cdb[1] = 0x0;
524 cp->cp_cdb[2] = 0x40 | 0x33;
525 cp->cp_cdb[7] = 1;
526
527 cp->cp_datalen = htonl(512);
528
529 ospl = splcam();
530 result = dpt_send_eata_command(dpt, cp, dccb_busaddr,
531 EATA_CMD_DMA_SEND_CP,
532 10000, 0, 0, 0);
533 if (result != 0) {
534 printf("dpt%d WARNING: detect_cache() failed (%d) to send "
535 "EATA_CMD_DMA_SEND_CP\n", dpt->unit, result);
536 splx(ospl);
537 return;
538 }
539 /* Wait for two seconds for a response. This can be slow... */
540 for (ndx = 0;
541 (ndx < 20000) &&
542 !((status = dpt_inb(dpt, HA_RAUXSTAT)) & HA_AIRQ);
543 ndx++) {
544 DELAY(50);
545 }
546
547 /* Grab the status and clear interrupts */
548 status = dpt_inb(dpt, HA_RSTATUS);
549 splx(ospl);
550
551 /*
552 * Sanity check
553 */
554 if (buff[0] != 0x33) {
555 return;
556 }
557 bytes = DPT_HCP_LENGTH(buff);
558 param = DPT_HCP_FIRST(buff);
559
560 if (DPT_HCP_CODE(param) != 1) {
561 /*
562 * DPT Log Page layout error
563 */
564 printf("dpt%d: NOTICE: Log Page (1) layout error\n",
565 dpt->unit);
566 return;
567 }
568 if (!(param[4] & 0x4)) {
569 dpt->cache_type = DPT_NO_CACHE;
570 return;
571 }
572 while (DPT_HCP_CODE(param) != 6) {
573 param = DPT_HCP_NEXT(param);
574 if ((param < buff)
575 || (param >= &buff[bytes])) {
576 return;
577 }
578 }
579
580 if (param[4] & 0x2) {
581 /*
582 * Cache disabled
583 */
584 dpt->cache_type = DPT_NO_CACHE;
585 return;
586 }
587
588 if (param[4] & 0x4) {
589 dpt->cache_type = DPT_CACHE_WRITETHROUGH;
590 }
591
592 /* XXX This isn't correct. This log parameter only has two bytes.... */
593#if 0
594 dpt->cache_size = param[5]
595 | (param[6] << 8)
596 | (param[7] << 16)
597 | (param[8] << 24);
598#endif
599}
600
601static void
602dpt_poll(struct cam_sim *sim)
603{
604 dpt_intr(cam_sim_softc(sim));
605}
606
607static void
608dptexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
609{
610 struct dpt_ccb *dccb;
611 union ccb *ccb;
612 struct dpt_softc *dpt;
613 int s;
614
615 dccb = (struct dpt_ccb *)arg;
616 ccb = dccb->ccb;
617 dpt = (struct dpt_softc *)ccb->ccb_h.ccb_dpt_ptr;
618
619 if (error != 0) {
620 if (error != EFBIG)
621 printf("dpt%d: Unexepected error 0x%x returned from "
622 "bus_dmamap_load\n", dpt->unit, error);
623 if (ccb->ccb_h.status == CAM_REQ_INPROG) {
624 xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
625 ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
626 }
627 dptfreeccb(dpt, dccb);
628 xpt_done(ccb);
629 return;
630 }
631
632 if (nseg != 0) {
633 dpt_sg_t *sg;
634 bus_dma_segment_t *end_seg;
635 bus_dmasync_op_t op;
636
637 end_seg = dm_segs + nseg;
638
639 /* Copy the segments into our SG list */
640 sg = dccb->sg_list;
641 while (dm_segs < end_seg) {
642 sg->seg_len = htonl(dm_segs->ds_len);
643 sg->seg_addr = htonl(dm_segs->ds_addr);
644 sg++;
645 dm_segs++;
646 }
647
648 if (nseg > 1) {
649 dccb->eata_ccb.scatter = 1;
650 dccb->eata_ccb.cp_dataDMA = dccb->sg_busaddr;
651 dccb->eata_ccb.cp_datalen =
652 htonl(nseg * sizeof(dpt_sg_t));
653 } else {
654 dccb->eata_ccb.cp_dataDMA = dccb->sg_list[0].seg_addr;
655 dccb->eata_ccb.cp_datalen = dccb->sg_list[0].seg_len;
656 }
657
658 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
659 op = BUS_DMASYNC_PREREAD;
660 else
661 op = BUS_DMASYNC_PREWRITE;
662
663 bus_dmamap_sync(dpt->buffer_dmat, dccb->dmamap, op);
664
665 } else {
666 dccb->eata_ccb.cp_dataDMA = 0;
667 dccb->eata_ccb.cp_datalen = 0;
668 }
669
670 s = splcam();
671
672 /*
673 * Last time we need to check if this CCB needs to
674 * be aborted.
675 */
676 if (ccb->ccb_h.status != CAM_REQ_INPROG) {
677 if (nseg != 0)
678 bus_dmamap_unload(dpt->buffer_dmat, dccb->dmamap);
679 dptfreeccb(dpt, dccb);
680 xpt_done(ccb);
681 splx(s);
682 return;
683 }
684
685 dccb->state |= DCCB_ACTIVE;
686 ccb->ccb_h.status |= CAM_SIM_QUEUED;
687 LIST_INSERT_HEAD(&dpt->pending_ccb_list, &ccb->ccb_h, sim_links.le);
688 ccb->ccb_h.timeout_ch =
689 timeout(dpttimeout, (caddr_t)dccb,
690 (ccb->ccb_h.timeout * hz) / 1000);
691 if (dpt_send_eata_command(dpt, &dccb->eata_ccb,
692 dccb->eata_ccb.cp_busaddr,
693 EATA_CMD_DMA_SEND_CP, 0, 0, 0, 0) != 0) {
694 ccb->ccb_h.status = CAM_NO_HBA; /* HBA dead or just busy?? */
695 if (nseg != 0)
696 bus_dmamap_unload(dpt->buffer_dmat, dccb->dmamap);
697 dptfreeccb(dpt, dccb);
698 xpt_done(ccb);
699 }
700
701 splx(s);
702}
703
704static void
705dpt_action(struct cam_sim *sim, union ccb *ccb)
706{
707 struct dpt_softc *dpt;
708
709 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("dpt_action\n"));
710
711 dpt = (struct dpt_softc *)cam_sim_softc(sim);
712
713 if ((dpt->state & DPT_HA_SHUTDOWN_ACTIVE) != 0) {
714 xpt_print_path(ccb->ccb_h.path);
715 printf("controller is shutdown. Aborting CCB.\n");
716 ccb->ccb_h.status = CAM_NO_HBA;
717 xpt_done(ccb);
718 return;
719 }
720
721 switch (ccb->ccb_h.func_code) {
722 /* Common cases first */
723 case XPT_SCSI_IO: /* Execute the requested I/O operation */
724 {
725 struct ccb_scsiio *csio;
726 struct ccb_hdr *ccbh;
727 struct dpt_ccb *dccb;
728 struct eata_ccb *eccb;
729
730 csio = &ccb->csio;
731 ccbh = &ccb->ccb_h;
732 /* Max CDB length is 12 bytes */
733 if (csio->cdb_len > 12) {
734 ccb->ccb_h.status = CAM_REQ_INVALID;
735 xpt_done(ccb);
736 return;
737 }
738 if ((dccb = dptgetccb(dpt)) == NULL) {
739 int s;
740
741 s = splcam();
742 dpt->resource_shortage = 1;
743 splx(s);
744 xpt_freeze_simq(sim, /*count*/1);
745 ccb->ccb_h.status = CAM_REQUEUE_REQ;
746 xpt_done(ccb);
747 return;
748 }
749 eccb = &dccb->eata_ccb;
750
751 /* Link dccb and ccb so we can find one from the other */
752 dccb->ccb = ccb;
753 ccb->ccb_h.ccb_dccb_ptr = dccb;
754 ccb->ccb_h.ccb_dpt_ptr = dpt;
755
756 /*
757 * Explicitly set all flags so that the compiler can
758 * be smart about setting them.
759 */
760 eccb->SCSI_Reset = 0;
761 eccb->HBA_Init = 0;
762 eccb->Auto_Req_Sen = (ccb->ccb_h.flags & CAM_DIS_AUTOSENSE)
763 ? 0 : 1;
764 eccb->scatter = 0;
765 eccb->Quick = 0;
766 eccb->Interpret =
767 ccb->ccb_h.target_id == dpt->hostid[cam_sim_bus(sim)]
768 ? 1 : 0;
769 eccb->DataOut = (ccb->ccb_h.flags & CAM_DIR_OUT) ? 1 : 0;
770 eccb->DataIn = (ccb->ccb_h.flags & CAM_DIR_IN) ? 1 : 0;
771 eccb->reqlen = csio->sense_len;
772 eccb->cp_id = ccb->ccb_h.target_id;
773 eccb->cp_channel = cam_sim_bus(sim);
774 eccb->cp_LUN = ccb->ccb_h.target_lun;
775 eccb->cp_luntar = 0;
776 eccb->cp_dispri = (ccb->ccb_h.flags & CAM_DIS_DISCONNECT)
777 ? 0 : 1;
778 eccb->cp_identify = 1;
779
780 if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0
781 && csio->tag_action != CAM_TAG_ACTION_NONE) {
782 eccb->cp_msg[0] = csio->tag_action;
783 eccb->cp_msg[1] = dccb->tag;
784 } else {
785 eccb->cp_msg[0] = 0;
786 eccb->cp_msg[1] = 0;
787 }
788 eccb->cp_msg[2] = 0;
789
790 if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
791 if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
792 bcopy(csio->cdb_io.cdb_ptr,
793 eccb->cp_cdb, csio->cdb_len);
794 } else {
795 /* I guess I could map it in... */
796 ccb->ccb_h.status = CAM_REQ_INVALID;
797 dptfreeccb(dpt, dccb);
798 xpt_done(ccb);
799 return;
800 }
801 } else {
802 bcopy(csio->cdb_io.cdb_bytes,
803 eccb->cp_cdb, csio->cdb_len);
804 }
805 /*
806 * If we have any data to send with this command,
807 * map it into bus space.
808 */
809 /* Only use S/G if there is a transfer */
810 if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
811 if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
812 /*
813 * We've been given a pointer
814 * to a single buffer.
815 */
816 if ((ccbh->flags & CAM_DATA_PHYS) == 0) {
817 int s;
818 int error;
819
820 s = splsoftvm();
821 error =
822 bus_dmamap_load(dpt->buffer_dmat,
823 dccb->dmamap,
824 csio->data_ptr,
825 csio->dxfer_len,
826 dptexecuteccb,
827 dccb, /*flags*/0);
828 if (error == EINPROGRESS) {
829 /*
830 * So as to maintain ordering,
831 * freeze the controller queue
832 * until our mapping is
833 * returned.
834 */
835 xpt_freeze_simq(sim, 1);
836 dccb->state |= CAM_RELEASE_SIMQ;
837 }
838 splx(s);
839 } else {
840 struct bus_dma_segment seg;
841
842 /* Pointer to physical buffer */
843 seg.ds_addr =
844 (bus_addr_t)csio->data_ptr;
845 seg.ds_len = csio->dxfer_len;
846 dptexecuteccb(dccb, &seg, 1, 0);
847 }
848 } else {
849 struct bus_dma_segment *segs;
850
851 if ((ccbh->flags & CAM_DATA_PHYS) != 0)
852 panic("dpt_action - Physical "
853 "segment pointers "
854 "unsupported");
855
856 if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
857 panic("dpt_action - Virtual "
858 "segment addresses "
859 "unsupported");
860
861 /* Just use the segments provided */
862 segs = (struct bus_dma_segment *)csio->data_ptr;
863 dptexecuteccb(dccb, segs, csio->sglist_cnt, 0);
864 }
865 } else {
866 /*
867 * XXX JGibbs.
868 * Does it want them both on or both off?
869 * CAM_DIR_NONE is both on, so this code can
870 * be removed if this is also what the DPT
871 * exptects.
872 */
873 eccb->DataOut = 0;
874 eccb->DataIn = 0;
875 dptexecuteccb(dccb, NULL, 0, 0);
876 }
877 break;
878 }
879 case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
880 case XPT_ABORT: /* Abort the specified CCB */
881 /* XXX Implement */
882 ccb->ccb_h.status = CAM_REQ_INVALID;
883 xpt_done(ccb);
884 break;
885 case XPT_SET_TRAN_SETTINGS:
886 {
887 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
888 xpt_done(ccb);
889 break;
890 }
891 case XPT_GET_TRAN_SETTINGS:
892 /* Get default/user set transfer settings for the target */
893 {
894 struct ccb_trans_settings *cts;
895 u_int target_mask;
896
897 cts = &ccb->cts;
898 target_mask = 0x01 << ccb->ccb_h.target_id;
899 if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
900 cts->flags = CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB;
901 cts->bus_width = (dpt->max_id > 7)
902 ? MSG_EXT_WDTR_BUS_8_BIT
903 : MSG_EXT_WDTR_BUS_16_BIT;
904 cts->sync_period = 25; /* 10MHz */
905
906 if (cts->sync_period != 0)
907 cts->sync_offset = 15;
908
909 cts->valid = CCB_TRANS_SYNC_RATE_VALID
910 | CCB_TRANS_SYNC_OFFSET_VALID
911 | CCB_TRANS_BUS_WIDTH_VALID
912 | CCB_TRANS_DISC_VALID
913 | CCB_TRANS_TQ_VALID;
914 ccb->ccb_h.status = CAM_REQ_CMP;
915 } else {
916 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
917 }
918 xpt_done(ccb);
919 break;
920 }
921 case XPT_CALC_GEOMETRY:
922 {
923 struct ccb_calc_geometry *ccg;
924 u_int32_t size_mb;
925 u_int32_t secs_per_cylinder;
926 int extended;
927
928 /*
929 * XXX Use Adaptec translation until I find out how to
930 * get this information from the card.
931 */
932 ccg = &ccb->ccg;
933 size_mb = ccg->volume_size
934 / ((1024L * 1024L) / ccg->block_size);
935 extended = 1;
936
937 if (size_mb > 1024 && extended) {
938 ccg->heads = 255;
939 ccg->secs_per_track = 63;
940 } else {
941 ccg->heads = 64;
942 ccg->secs_per_track = 32;
943 }
944 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
945 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
946 ccb->ccb_h.status = CAM_REQ_CMP;
947 xpt_done(ccb);
948 break;
949 }
950 case XPT_RESET_BUS: /* Reset the specified SCSI bus */
951 {
952 /* XXX Implement */
953 ccb->ccb_h.status = CAM_REQ_CMP;
954 xpt_done(ccb);
955 break;
956 }
957 case XPT_TERM_IO: /* Terminate the I/O process */
958 /* XXX Implement */
959 ccb->ccb_h.status = CAM_REQ_INVALID;
960 xpt_done(ccb);
961 break;
962 case XPT_PATH_INQ: /* Path routing inquiry */
963 {
964 struct ccb_pathinq *cpi = &ccb->cpi;
965
966 cpi->version_num = 1;
967 cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
968 if (dpt->max_id > 7)
969 cpi->hba_inquiry |= PI_WIDE_16;
970 cpi->target_sprt = 0;
971 cpi->hba_misc = 0;
972 cpi->hba_eng_cnt = 0;
973 cpi->max_target = dpt->max_id;
974 cpi->max_lun = dpt->max_lun;
975 cpi->initiator_id = dpt->hostid[cam_sim_bus(sim)];
976 cpi->bus_id = cam_sim_bus(sim);
977 cpi->base_transfer_speed = 3300;
978 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
979 strncpy(cpi->hba_vid, "DPT", HBA_IDLEN);
980 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
981 cpi->unit_number = cam_sim_unit(sim);
982 cpi->ccb_h.status = CAM_REQ_CMP;
983 xpt_done(ccb);
984 break;
985 }
986 default:
987 ccb->ccb_h.status = CAM_REQ_INVALID;
988 xpt_done(ccb);
989 break;
990 }
991}
992
993/*
994 * This routine will try to send an EATA command to the DPT HBA.
995 * It will, by default, try 20,000 times, waiting 50us between tries.
996 * It returns 0 on success and 1 on failure.
997 * It is assumed to be called at splcam().
998 */
999static int
1000dpt_send_eata_command(dpt_softc_t *dpt, eata_ccb_t *cmd_block,
1001 u_int32_t cmd_busaddr, u_int command, u_int retries,
1002 u_int ifc, u_int code, u_int code2)
1003{
1004 u_int loop;
1005
1006 if (!retries)
1007 retries = 20000;
1008
1009 /*
1010 * I hate this polling nonsense. Wish there was a way to tell the DPT
1011 * to go get commands at its own pace, or to interrupt when ready.
1012 * In the mean time we will measure how many itterations it really
1013 * takes.
1014 */
1015 for (loop = 0; loop < retries; loop++) {
1016 if ((dpt_inb(dpt, HA_RAUXSTAT) & HA_ABUSY) == 0)
1017 break;
1018 else
1019 DELAY(50);
1020 }
1021
1022 if (loop < retries) {
1023#ifdef DPT_MEASURE_PERFORMANCE
1024 if (loop > dpt->performance.max_eata_tries)
1025 dpt->performance.max_eata_tries = loop;
1026
1027 if (loop < dpt->performance.min_eata_tries)
1028 dpt->performance.min_eata_tries = loop;
1029#endif
1030 } else {
1031#ifdef DPT_MEASURE_PERFORMANCE
1032 ++dpt->performance.command_too_busy;
1033#endif
1034 return (1);
1035 }
1036
1037 /* The controller is alive, advance the wedge timer */
1038#ifdef DPT_RESET_HBA
1039 dpt->last_contact = microtime_now;
1040#endif
1041
1042 if (cmd_block == NULL)
1043 cmd_busaddr = 0;
1044#if (BYTE_ORDER == BIG_ENDIAN)
1045 else {
1046 cmd_busaddr = ((cmd_busaddr >> 24) & 0xFF)
1047 | ((cmd_busaddr >> 16) & 0xFF)
1048 | ((cmd_busaddr >> 8) & 0xFF)
1049 | (cmd_busaddr & 0xFF);
1050 }
1051#endif
1052 /* And now the address */
1053 dpt_outl(dpt, HA_WDMAADDR, cmd_busaddr);
1054
1055 if (command == EATA_CMD_IMMEDIATE) {
1056 if (cmd_block == NULL) {
1057 dpt_outb(dpt, HA_WCODE2, code2);
1058 dpt_outb(dpt, HA_WCODE, code);
1059 }
1060 dpt_outb(dpt, HA_WIFC, ifc);
1061 }
1062 dpt_outb(dpt, HA_WCOMMAND, command);
1063
1064 return (0);
1065}
1066
1067
1068/* ==================== Exported Function definitions =======================*/
1069struct dpt_softc *
1070dpt_alloc(u_int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
1071{
1072 struct dpt_softc *dpt;
1073 int i;
1074
1075 dpt = (struct dpt_softc *)malloc(sizeof(*dpt), M_DEVBUF, M_NOWAIT);
1076 if (dpt == NULL) {
1077 printf("dpt%d: Unable to allocate softc\n", dpt->unit);
1078 return (NULL);
1079 }
1080
1081 bzero(dpt, sizeof(dpt_softc_t));
1082 dpt->tag = tag;
1083 dpt->bsh = bsh;
1084 dpt->unit = unit;
1085 SLIST_INIT(&dpt->free_dccb_list);
1086 LIST_INIT(&dpt->pending_ccb_list);
1087 TAILQ_INSERT_TAIL(&dpt_softcs, dpt, links);
1088 for (i = 0; i < MAX_CHANNELS; i++)
1089 dpt->resetlevel[i] = DPT_HA_OK;
1090
1091#ifdef DPT_MEASURE_PERFORMANCE
1092 dpt_reset_performance(dpt);
1093#endif /* DPT_MEASURE_PERFORMANCE */
1094 return (dpt);
1095}
1096
1097void
1098dpt_free(struct dpt_softc *dpt)
1099{
1100 switch (dpt->init_level) {
1101 default:
1102 case 5:
1103 bus_dmamap_unload(dpt->dccb_dmat, dpt->dccb_dmamap);
1104 case 4:
1105 bus_dmamem_free(dpt->dccb_dmat, dpt->dpt_dccbs,
1106 dpt->dccb_dmamap);
1107 bus_dmamap_destroy(dpt->dccb_dmat, dpt->dccb_dmamap);
1108 case 3:
1109 bus_dma_tag_destroy(dpt->dccb_dmat);
1110 case 2:
1111 bus_dma_tag_destroy(dpt->buffer_dmat);
1112 case 1:
1113 {
1114 struct sg_map_node *sg_map;
1115
1116 while ((sg_map = SLIST_FIRST(&dpt->sg_maps)) != NULL) {
1117 SLIST_REMOVE_HEAD(&dpt->sg_maps, links);
1118 bus_dmamap_unload(dpt->sg_dmat,
1119 sg_map->sg_dmamap);
1120 bus_dmamem_free(dpt->sg_dmat, sg_map->sg_vaddr,
1121 sg_map->sg_dmamap);
1122 free(sg_map, M_DEVBUF);
1123 }
1124 bus_dma_tag_destroy(dpt->sg_dmat);
1125 }
1126 case 0:
1127 break;
1128 }
1129 TAILQ_REMOVE(&dpt_softcs, dpt, links);
1130 free(dpt, M_DEVBUF);
1131}
1132
1133static u_int8_t string_sizes[] =
1134{
1135 sizeof(((dpt_inq_t*)NULL)->vendor),
1136 sizeof(((dpt_inq_t*)NULL)->modelNum),
1137 sizeof(((dpt_inq_t*)NULL)->firmware),
1138 sizeof(((dpt_inq_t*)NULL)->protocol),
1139};
1140
1141int
1142dpt_init(struct dpt_softc *dpt)
1143{
1144 dpt_conf_t conf;
1145 struct sg_map_node *sg_map;
1146 dpt_ccb_t *dccb;
1147 u_int8_t *strp;
1148 int index;
1149 int i;
1150 int retval;
1151
1152 dpt->init_level = 0;
1153 SLIST_INIT(&dpt->sg_maps);
1154
1155#ifdef DPT_RESET_BOARD
1156 printf("dpt%d: resetting HBA\n", dpt->unit);
1157 dpt_outb(dpt, HA_WCOMMAND, EATA_CMD_RESET);
1158 DELAY(750000);
1159 /* XXX Shouldn't we poll a status register or something??? */
1160#endif
1161 /* DMA tag for our S/G structures. We allocate in page sized chunks */
1162 if (bus_dma_tag_create(dpt->parent_dmat, /*alignment*/1, /*boundary*/0,
1163 /*lowaddr*/BUS_SPACE_MAXADDR,
1164 /*highaddr*/BUS_SPACE_MAXADDR,
1165 /*filter*/NULL, /*filterarg*/NULL,
1166 PAGE_SIZE, /*nsegments*/1,
1167 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
1168 /*flags*/0, &dpt->sg_dmat) != 0) {
1169 goto error_exit;
1170 }
1171
1172 dpt->init_level++;
1173
1174 /*
1175 * We allocate our DPT ccbs as a contiguous array of bus dma'able
1176 * memory. To get the allocation size, we need to know how many
1177 * ccbs the card supports. This requires a ccb. We solve this
1178 * chicken and egg problem by allocating some re-usable S/G space
1179 * up front, and treating it as our status packet, CCB, and target
1180 * memory space for these commands.
1181 */
1182 sg_map = dptallocsgmap(dpt);
1183 if (sg_map == NULL)
1184 goto error_exit;
1185
1186 dpt->sp = (volatile dpt_sp_t *)sg_map->sg_vaddr;
1187 dccb = (struct dpt_ccb *)&dpt->sp[1];
1188 bzero(dccb, sizeof(*dccb));
1189 dpt->sp_physaddr = sg_map->sg_physaddr;
1190 dccb->eata_ccb.cp_dataDMA =
1191 htonl(sg_map->sg_physaddr + sizeof(dpt_sp_t) + sizeof(*dccb));
1192 dccb->eata_ccb.cp_busaddr = ~0;
1193 dccb->eata_ccb.cp_statDMA = htonl(dpt->sp_physaddr);
1194 dccb->eata_ccb.cp_reqDMA = htonl(dpt->sp_physaddr + sizeof(*dccb)
1195 + offsetof(struct dpt_ccb, sense_data));
1196
1197 /* Okay. Fetch our config */
1198 bzero(&dccb[1], sizeof(conf)); /* data area */
1199 retval = dpt_get_conf(dpt, dccb, sg_map->sg_physaddr + sizeof(dpt_sp_t),
1200 sizeof(conf), 0xc1, 7, 1);
1201
1202 if (retval != 0) {
1203 printf("dpt%d: Failed to get board configuration\n", dpt->unit);
1204 return (retval);
1205 }
1206 bcopy(&dccb[1], &conf, sizeof(conf));
1207
1208 bzero(&dccb[1], sizeof(dpt->board_data));
1209 retval = dpt_get_conf(dpt, dccb, sg_map->sg_physaddr + sizeof(dpt_sp_t),
1210 sizeof(dpt->board_data), 0, conf.scsi_id0, 0);
1211 if (retval != 0) {
1212 printf("dpt%d: Failed to get inquiry information\n", dpt->unit);
1213 return (retval);
1214 }
1215 bcopy(&dccb[1], &dpt->board_data, sizeof(dpt->board_data));
1216
1217 dpt_detect_cache(dpt, dccb, sg_map->sg_physaddr + sizeof(dpt_sp_t),
1218 (u_int8_t *)&dccb[1]);
1219
1220 switch (ntohl(conf.splen)) {
1221 case DPT_EATA_REVA:
1222 dpt->EATA_revision = 'a';
1223 break;
1224 case DPT_EATA_REVB:
1225 dpt->EATA_revision = 'b';
1226 break;
1227 case DPT_EATA_REVC:
1228 dpt->EATA_revision = 'c';
1229 break;
1230 case DPT_EATA_REVZ:
1231 dpt->EATA_revision = 'z';
1232 break;
1233 default:
1234 dpt->EATA_revision = '?';
1235 }
1236
1237 dpt->max_id = conf.MAX_ID;
1238 dpt->max_lun = conf.MAX_LUN;
1239 dpt->irq = conf.IRQ;
1240 dpt->dma_channel = (8 - conf.DMA_channel) & 7;
1241 dpt->channels = conf.MAX_CHAN + 1;
1242 dpt->state |= DPT_HA_OK;
1243 if (conf.SECOND)
1244 dpt->primary = FALSE;
1245 else
1246 dpt->primary = TRUE;
1247
1248 dpt->more_support = conf.MORE_support;
1249
1250 if (strncmp(dpt->board_data.firmware, "07G0", 4) >= 0)
1251 dpt->immediate_support = 1;
1252 else
1253 dpt->immediate_support = 0;
1254
1255 dpt->broken_INQUIRY = FALSE;
1256
1257 dpt->cplen = ntohl(conf.cplen);
1258 dpt->cppadlen = ntohs(conf.cppadlen);
1259 dpt->max_dccbs = ntohs(conf.queuesiz);
1260
1261 if (dpt->max_dccbs > 256) {
1262 printf("dpt%d: Max CCBs reduced from %d to "
1263 "256 due to tag algorithm\n", dpt->unit, dpt->max_dccbs);
1264 dpt->max_dccbs = 256;
1265 }
1266
1267 dpt->hostid[0] = conf.scsi_id0;
1268 dpt->hostid[1] = conf.scsi_id1;
1269 dpt->hostid[2] = conf.scsi_id2;
1270
1271 if (conf.SG_64K)
1272 dpt->sgsize = 8192;
1273 else
1274 dpt->sgsize = ntohs(conf.SGsiz);
1275
1276 /* We can only get 64k buffers, so don't bother to waste space. */
1277 if (dpt->sgsize < 17 || dpt->sgsize > 32)
1278 dpt->sgsize = 32;
1279
1280 if (dpt->sgsize > dpt_max_segs)
1281 dpt->sgsize = dpt_max_segs;
1282
1283 /* DMA tag for mapping buffers into device visible space. */
1284 if (bus_dma_tag_create(dpt->parent_dmat, /*alignment*/1, /*boundary*/0,
1285 /*lowaddr*/BUS_SPACE_MAXADDR,
1286 /*highaddr*/BUS_SPACE_MAXADDR,
1287 /*filter*/NULL, /*filterarg*/NULL,
1288 /*maxsize*/MAXBSIZE, /*nsegments*/dpt->sgsize,
1289 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
1290 /*flags*/BUS_DMA_ALLOCNOW,
1291 &dpt->buffer_dmat) != 0) {
1292 goto error_exit;
1293 }
1294
1295 dpt->init_level++;
1296
1297 /* DMA tag for our ccb structures and interrupt status packet */
1298 if (bus_dma_tag_create(dpt->parent_dmat, /*alignment*/1, /*boundary*/0,
1299 /*lowaddr*/BUS_SPACE_MAXADDR,
1300 /*highaddr*/BUS_SPACE_MAXADDR,
1301 /*filter*/NULL, /*filterarg*/NULL,
1302 (dpt->max_dccbs * sizeof(struct dpt_ccb))
1303 + sizeof(dpt_sp_t),
1304 /*nsegments*/1,
1305 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
1306 /*flags*/0, &dpt->dccb_dmat) != 0) {
1307 goto error_exit;
1308 }
1309
1310 dpt->init_level++;
1311
1312 /* Allocation for our ccbs and interrupt status packet */
1313 if (bus_dmamem_alloc(dpt->dccb_dmat, (void **)&dpt->dpt_dccbs,
1314 BUS_DMA_NOWAIT, &dpt->dccb_dmamap) != 0) {
1315 goto error_exit;
1316 }
1317
1318 dpt->init_level++;
1319
1320 /* And permanently map them */
1321 bus_dmamap_load(dpt->dccb_dmat, dpt->dccb_dmamap,
1322 dpt->dpt_dccbs,
1323 (dpt->max_dccbs * sizeof(struct dpt_ccb))
1324 + sizeof(dpt_sp_t),
1325 dptmapmem, &dpt->dpt_ccb_busbase, /*flags*/0);
1326
1327 /* Clear them out. */
1328 bzero(dpt->dpt_dccbs,
1329 (dpt->max_dccbs * sizeof(struct dpt_ccb)) + sizeof(dpt_sp_t));
1330
1331 dpt->dpt_ccb_busend = dpt->dpt_ccb_busbase;
1332
1333 dpt->sp = (dpt_sp_t*)&dpt->dpt_dccbs[dpt->max_dccbs];
1334 dpt->sp_physaddr = dpt->dpt_ccb_busbase
1335 + (dpt->max_dccbs * sizeof(dpt_ccb_t));
1336 dpt->init_level++;
1337
1338 /* Allocate our first batch of ccbs */
1339 if (dptallocccbs(dpt) == 0)
1340 return (2);
1341
1342 /* Prepare for Target Mode */
1343 dpt->target_mode_enabled = 1;
1344
1345 /* Nuke excess spaces from inquiry information */
1346 strp = dpt->board_data.vendor;
1347 for (i = 0; i < sizeof(string_sizes); i++) {
1348 index = string_sizes[i] - 1;
1349 while (index && (strp[index] == ' '))
1350 strp[index--] = '\0';
1351 strp += string_sizes[i];
1352 }
1353
1354 printf("dpt%d: %.8s %.16s FW Rev. %.4s, ",
1355 dpt->unit, dpt->board_data.vendor,
1356 dpt->board_data.modelNum, dpt->board_data.firmware);
1357
1358 printf("%d channel%s, ", dpt->channels, dpt->channels > 1 ? "s" : "");
1359
1360 if (dpt->cache_type != DPT_NO_CACHE
1361 && dpt->cache_size != 0) {
1362 printf("%s Cache, ",
1363 dpt->cache_type == DPT_CACHE_WRITETHROUGH
1364 ? "Write-Through" : "Write-Back");
1365 }
1366
1367 printf("%d CCBs\n", dpt->max_dccbs);
1368 return (0);
1369
1370error_exit:
1371 return (1);
1372}
1373
1374int
1375dpt_attach(dpt_softc_t *dpt)
1376{
1377 struct cam_devq *devq;
1378 int i;
1379
1380 /*
1381 * Create the device queue for our SIM.
1382 */
1383 devq = cam_simq_alloc(dpt->max_dccbs);
1384 if (devq == NULL)
1385 return (0);
1386
1387 for (i = 0; i < dpt->channels; i++) {
1388 /*
1389 * Construct our SIM entry
1390 */
1391 dpt->sims[i] = cam_sim_alloc(dpt_action, dpt_poll, "dpt",
1392 dpt, dpt->unit, /*untagged*/2,
1393 /*tagged*/dpt->max_dccbs, devq);
1394 if (xpt_bus_register(dpt->sims[i], i) != CAM_SUCCESS) {
1395 cam_sim_free(dpt->sims[i], /*free_devq*/i == 0);
1396 break;
1397 }
1398
1399 if (xpt_create_path(&dpt->paths[i], /*periph*/NULL,
1400 cam_sim_path(dpt->sims[i]),
1401 CAM_TARGET_WILDCARD,
1402 CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1403 xpt_bus_deregister(cam_sim_path(dpt->sims[i]));
1404 cam_sim_free(dpt->sims[i], /*free_devq*/i == 0);
1405 break;
1406 }
1407
1408 }
1409 if (i > 0)
159
160/* ================= Private Inline Function definitions ====================*/
161static __inline int
162dpt_just_reset(dpt_softc_t * dpt)
163{
164 if ((dpt_inb(dpt, 2) == 'D')
165 && (dpt_inb(dpt, 3) == 'P')
166 && (dpt_inb(dpt, 4) == 'T')
167 && (dpt_inb(dpt, 5) == 'H'))
168 return (1);
169 else
170 return (0);
171}
172
173static __inline int
174dpt_raid_busy(dpt_softc_t * dpt)
175{
176 if ((dpt_inb(dpt, 0) == 'D')
177 && (dpt_inb(dpt, 1) == 'P')
178 && (dpt_inb(dpt, 2) == 'T'))
179 return (1);
180 else
181 return (0);
182}
183
184static __inline int
185dpt_wait(dpt_softc_t *dpt, u_int bits, u_int state)
186{
187 int i;
188 u_int c;
189
190 for (i = 0; i < 20000; i++) { /* wait 20ms for not busy */
191 c = dpt_inb(dpt, HA_RSTATUS) & bits;
192 if (c == state)
193 return (0);
194 else
195 DELAY(50);
196 }
197 return (-1);
198}
199
200static __inline struct dpt_ccb*
201dptgetccb(struct dpt_softc *dpt)
202{
203 struct dpt_ccb* dccb;
204 int s;
205
206 s = splcam();
207 if ((dccb = SLIST_FIRST(&dpt->free_dccb_list)) != NULL) {
208 SLIST_REMOVE_HEAD(&dpt->free_dccb_list, links);
209 dpt->free_dccbs--;
210 } else if (dpt->total_dccbs < dpt->max_dccbs) {
211 dptallocccbs(dpt);
212 dccb = SLIST_FIRST(&dpt->free_dccb_list);
213 if (dccb == NULL)
214 printf("dpt%d: Can't malloc DCCB\n", dpt->unit);
215 else {
216 SLIST_REMOVE_HEAD(&dpt->free_dccb_list, links);
217 dpt->free_dccbs--;
218 }
219 }
220 splx(s);
221
222 return (dccb);
223}
224
225static __inline void
226dptfreeccb(struct dpt_softc *dpt, struct dpt_ccb *dccb)
227{
228 int s;
229
230 s = splcam();
231 if ((dccb->state & DCCB_ACTIVE) != 0)
232 LIST_REMOVE(&dccb->ccb->ccb_h, sim_links.le);
233 if ((dccb->state & DCCB_RELEASE_SIMQ) != 0)
234 dccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
235 else if (dpt->resource_shortage != 0
236 && (dccb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
237 dccb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
238 dpt->resource_shortage = FALSE;
239 }
240 dccb->state = DCCB_FREE;
241 SLIST_INSERT_HEAD(&dpt->free_dccb_list, dccb, links);
242 ++dpt->free_dccbs;
243 splx(s);
244}
245
246static __inline u_int32_t
247dptccbvtop(struct dpt_softc *dpt, struct dpt_ccb *dccb)
248{
249 return (dpt->dpt_ccb_busbase
250 + (u_int32_t)((caddr_t)dccb - (caddr_t)dpt->dpt_dccbs));
251}
252
253static __inline struct dpt_ccb *
254dptccbptov(struct dpt_softc *dpt, u_int32_t busaddr)
255{
256 return (dpt->dpt_dccbs
257 + ((struct dpt_ccb *)busaddr
258 - (struct dpt_ccb *)dpt->dpt_ccb_busbase));
259}
260
261/*
262 * Send a command for immediate execution by the DPT
263 * See above function for IMPORTANT notes.
264 */
265static __inline int
266dpt_send_immediate(dpt_softc_t *dpt, eata_ccb_t *cmd_block,
267 u_int32_t cmd_busaddr, u_int retries,
268 u_int ifc, u_int code, u_int code2)
269{
270 return (dpt_send_eata_command(dpt, cmd_block, cmd_busaddr,
271 EATA_CMD_IMMEDIATE, retries, ifc,
272 code, code2));
273}
274
275
276/* ===================== Private Function definitions =======================*/
277static void
278dptmapmem(void *arg, bus_dma_segment_t *segs, int nseg, int error)
279{
280 bus_addr_t *busaddrp;
281
282 busaddrp = (bus_addr_t *)arg;
283 *busaddrp = segs->ds_addr;
284}
285
286static struct sg_map_node *
287dptallocsgmap(struct dpt_softc *dpt)
288{
289 struct sg_map_node *sg_map;
290
291 sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
292
293 if (sg_map == NULL)
294 return (NULL);
295
296 /* Allocate S/G space for the next batch of CCBS */
297 if (bus_dmamem_alloc(dpt->sg_dmat, (void **)&sg_map->sg_vaddr,
298 BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
299 free(sg_map, M_DEVBUF);
300 return (NULL);
301 }
302
303 (void)bus_dmamap_load(dpt->sg_dmat, sg_map->sg_dmamap, sg_map->sg_vaddr,
304 PAGE_SIZE, dptmapmem, &sg_map->sg_physaddr,
305 /*flags*/0);
306
307 SLIST_INSERT_HEAD(&dpt->sg_maps, sg_map, links);
308
309 return (sg_map);
310}
311
312/*
313 * Allocate another chunk of CCB's. Return count of entries added.
314 * Assumed to be called at splcam().
315 */
316static int
317dptallocccbs(dpt_softc_t *dpt)
318{
319 struct dpt_ccb *next_ccb;
320 struct sg_map_node *sg_map;
321 bus_addr_t physaddr;
322 dpt_sg_t *segs;
323 int newcount;
324 int i;
325
326 next_ccb = &dpt->dpt_dccbs[dpt->total_dccbs];
327
328 if (next_ccb == dpt->dpt_dccbs) {
329 /*
330 * First time through. Re-use the S/G
331 * space we allocated for initialization
332 * CCBS.
333 */
334 sg_map = SLIST_FIRST(&dpt->sg_maps);
335 } else {
336 sg_map = dptallocsgmap(dpt);
337 }
338
339 if (sg_map == NULL)
340 return (0);
341
342 segs = sg_map->sg_vaddr;
343 physaddr = sg_map->sg_physaddr;
344
345 newcount = (PAGE_SIZE / (dpt->sgsize * sizeof(dpt_sg_t)));
346 for (i = 0; dpt->total_dccbs < dpt->max_dccbs && i < newcount; i++) {
347 int error;
348
349 error = bus_dmamap_create(dpt->buffer_dmat, /*flags*/0,
350 &next_ccb->dmamap);
351 if (error != 0)
352 break;
353 next_ccb->sg_list = segs;
354 next_ccb->sg_busaddr = htonl(physaddr);
355 next_ccb->eata_ccb.cp_dataDMA = htonl(physaddr);
356 next_ccb->eata_ccb.cp_statDMA = htonl(dpt->sp_physaddr);
357 next_ccb->eata_ccb.cp_reqDMA =
358 htonl(dptccbvtop(dpt, next_ccb)
359 + offsetof(struct dpt_ccb, sense_data));
360 next_ccb->eata_ccb.cp_busaddr = dpt->dpt_ccb_busend;
361 next_ccb->state = DCCB_FREE;
362 next_ccb->tag = dpt->total_dccbs;
363 SLIST_INSERT_HEAD(&dpt->free_dccb_list, next_ccb, links);
364 segs += dpt->sgsize;
365 physaddr += (dpt->sgsize * sizeof(dpt_sg_t));
366 dpt->dpt_ccb_busend += sizeof(*next_ccb);
367 next_ccb++;
368 dpt->total_dccbs++;
369 }
370 return (i);
371}
372
373/*
374 * Read a configuration page into the supplied dpt_cont_t buffer.
375 */
376static int
377dpt_get_conf(dpt_softc_t *dpt, dpt_ccb_t *dccb, u_int32_t dccb_busaddr,
378 u_int size, u_int page, u_int target, int extent)
379{
380 eata_ccb_t *cp;
381
382 u_int8_t status;
383
384 int ndx;
385 int ospl;
386 int result;
387
388 cp = &dccb->eata_ccb;
389 bzero((void *)dpt->sp, sizeof(*dpt->sp));
390
391 cp->Interpret = 1;
392 cp->DataIn = 1;
393 cp->Auto_Req_Sen = 1;
394 cp->reqlen = sizeof(struct scsi_sense_data);
395
396 cp->cp_id = target;
397 cp->cp_LUN = 0; /* In the EATA packet */
398 cp->cp_lun = 0; /* In the SCSI command */
399
400 cp->cp_scsi_cmd = INQUIRY;
401 cp->cp_len = size;
402
403 cp->cp_extent = extent;
404
405 cp->cp_page = page;
406 cp->cp_channel = 0; /* DNC, Interpret mode is set */
407 cp->cp_identify = 1;
408 cp->cp_datalen = htonl(size);
409
410 ospl = splcam();
411
412 /*
413 * This could be a simple for loop, but we suspected the compiler To
414 * have optimized it a bit too much. Wait for the controller to
415 * become ready
416 */
417 while (((status = dpt_inb(dpt, HA_RSTATUS)) != (HA_SREADY | HA_SSC)
418 && (status != (HA_SREADY | HA_SSC | HA_SERROR))
419 && (status != (HA_SDRDY | HA_SERROR | HA_SDRQ)))
420 || (dpt_wait(dpt, HA_SBUSY, 0))) {
421
422 /*
423 * RAID Drives still Spinning up? (This should only occur if
424 * the DPT controller is in a NON PC (PCI?) platform).
425 */
426 if (dpt_raid_busy(dpt)) {
427 printf("dpt%d WARNING: Get_conf() RSUS failed.\n",
428 dpt->unit);
429 splx(ospl);
430 return (0);
431 }
432 }
433
434 DptStat_Reset_BUSY(dpt->sp);
435
436 /*
437 * XXXX We might want to do something more clever than aborting at
438 * this point, like resetting (rebooting) the controller and trying
439 * again.
440 */
441 if ((result = dpt_send_eata_command(dpt, cp, dccb_busaddr,
442 EATA_CMD_DMA_SEND_CP,
443 10000, 0, 0, 0)) != 0) {
444 printf("dpt%d WARNING: Get_conf() failed (%d) to send "
445 "EATA_CMD_DMA_READ_CONFIG\n",
446 dpt->unit, result);
447 splx(ospl);
448 return (0);
449 }
450 /* Wait for two seconds for a response. This can be slow */
451 for (ndx = 0;
452 (ndx < 20000)
453 && !((status = dpt_inb(dpt, HA_RAUXSTAT)) & HA_AIRQ);
454 ndx++) {
455 DELAY(50);
456 }
457
458 /* Grab the status and clear interrupts */
459 status = dpt_inb(dpt, HA_RSTATUS);
460
461 splx(ospl);
462
463 /*
464 * Check the status carefully. Return only if the
465 * command was successful.
466 */
467 if (((status & HA_SERROR) == 0)
468 && (dpt->sp->hba_stat == 0)
469 && (dpt->sp->scsi_stat == 0)
470 && (dpt->sp->residue_len == 0))
471 return (0);
472 return (1);
473}
474
475/* Detect Cache parameters and size */
476static void
477dpt_detect_cache(dpt_softc_t *dpt, dpt_ccb_t *dccb, u_int32_t dccb_busaddr,
478 u_int8_t *buff)
479{
480 eata_ccb_t *cp;
481 u_int8_t *param;
482 int bytes;
483 int result;
484 int ospl;
485 int ndx;
486 u_int8_t status;
487
488 /*
489 * Default setting, for best perfromance..
490 * This is what virtually all cards default to..
491 */
492 dpt->cache_type = DPT_CACHE_WRITEBACK;
493 dpt->cache_size = 0;
494
495 cp = &dccb->eata_ccb;
496 bzero((void *)dpt->sp, sizeof(dpt->sp));
497 bzero(buff, 512);
498
499 /* Setup the command structure */
500 cp->Interpret = 1;
501 cp->DataIn = 1;
502 cp->Auto_Req_Sen = 1;
503 cp->reqlen = sizeof(struct scsi_sense_data);
504
505 cp->cp_id = 0; /* who cares? The HBA will interpret.. */
506 cp->cp_LUN = 0; /* In the EATA packet */
507 cp->cp_lun = 0; /* In the SCSI command */
508 cp->cp_channel = 0;
509
510 cp->cp_scsi_cmd = EATA_CMD_DMA_SEND_CP;
511 cp->cp_len = 56;
512
513 cp->cp_extent = 0;
514 cp->cp_page = 0;
515 cp->cp_identify = 1;
516 cp->cp_dispri = 1;
517
518 /*
519 * Build the EATA Command Packet structure
520 * for a Log Sense Command.
521 */
522 cp->cp_cdb[0] = 0x4d;
523 cp->cp_cdb[1] = 0x0;
524 cp->cp_cdb[2] = 0x40 | 0x33;
525 cp->cp_cdb[7] = 1;
526
527 cp->cp_datalen = htonl(512);
528
529 ospl = splcam();
530 result = dpt_send_eata_command(dpt, cp, dccb_busaddr,
531 EATA_CMD_DMA_SEND_CP,
532 10000, 0, 0, 0);
533 if (result != 0) {
534 printf("dpt%d WARNING: detect_cache() failed (%d) to send "
535 "EATA_CMD_DMA_SEND_CP\n", dpt->unit, result);
536 splx(ospl);
537 return;
538 }
539 /* Wait for two seconds for a response. This can be slow... */
540 for (ndx = 0;
541 (ndx < 20000) &&
542 !((status = dpt_inb(dpt, HA_RAUXSTAT)) & HA_AIRQ);
543 ndx++) {
544 DELAY(50);
545 }
546
547 /* Grab the status and clear interrupts */
548 status = dpt_inb(dpt, HA_RSTATUS);
549 splx(ospl);
550
551 /*
552 * Sanity check
553 */
554 if (buff[0] != 0x33) {
555 return;
556 }
557 bytes = DPT_HCP_LENGTH(buff);
558 param = DPT_HCP_FIRST(buff);
559
560 if (DPT_HCP_CODE(param) != 1) {
561 /*
562 * DPT Log Page layout error
563 */
564 printf("dpt%d: NOTICE: Log Page (1) layout error\n",
565 dpt->unit);
566 return;
567 }
568 if (!(param[4] & 0x4)) {
569 dpt->cache_type = DPT_NO_CACHE;
570 return;
571 }
572 while (DPT_HCP_CODE(param) != 6) {
573 param = DPT_HCP_NEXT(param);
574 if ((param < buff)
575 || (param >= &buff[bytes])) {
576 return;
577 }
578 }
579
580 if (param[4] & 0x2) {
581 /*
582 * Cache disabled
583 */
584 dpt->cache_type = DPT_NO_CACHE;
585 return;
586 }
587
588 if (param[4] & 0x4) {
589 dpt->cache_type = DPT_CACHE_WRITETHROUGH;
590 }
591
592 /* XXX This isn't correct. This log parameter only has two bytes.... */
593#if 0
594 dpt->cache_size = param[5]
595 | (param[6] << 8)
596 | (param[7] << 16)
597 | (param[8] << 24);
598#endif
599}
600
601static void
602dpt_poll(struct cam_sim *sim)
603{
604 dpt_intr(cam_sim_softc(sim));
605}
606
607static void
608dptexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
609{
610 struct dpt_ccb *dccb;
611 union ccb *ccb;
612 struct dpt_softc *dpt;
613 int s;
614
615 dccb = (struct dpt_ccb *)arg;
616 ccb = dccb->ccb;
617 dpt = (struct dpt_softc *)ccb->ccb_h.ccb_dpt_ptr;
618
619 if (error != 0) {
620 if (error != EFBIG)
621 printf("dpt%d: Unexepected error 0x%x returned from "
622 "bus_dmamap_load\n", dpt->unit, error);
623 if (ccb->ccb_h.status == CAM_REQ_INPROG) {
624 xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
625 ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
626 }
627 dptfreeccb(dpt, dccb);
628 xpt_done(ccb);
629 return;
630 }
631
632 if (nseg != 0) {
633 dpt_sg_t *sg;
634 bus_dma_segment_t *end_seg;
635 bus_dmasync_op_t op;
636
637 end_seg = dm_segs + nseg;
638
639 /* Copy the segments into our SG list */
640 sg = dccb->sg_list;
641 while (dm_segs < end_seg) {
642 sg->seg_len = htonl(dm_segs->ds_len);
643 sg->seg_addr = htonl(dm_segs->ds_addr);
644 sg++;
645 dm_segs++;
646 }
647
648 if (nseg > 1) {
649 dccb->eata_ccb.scatter = 1;
650 dccb->eata_ccb.cp_dataDMA = dccb->sg_busaddr;
651 dccb->eata_ccb.cp_datalen =
652 htonl(nseg * sizeof(dpt_sg_t));
653 } else {
654 dccb->eata_ccb.cp_dataDMA = dccb->sg_list[0].seg_addr;
655 dccb->eata_ccb.cp_datalen = dccb->sg_list[0].seg_len;
656 }
657
658 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
659 op = BUS_DMASYNC_PREREAD;
660 else
661 op = BUS_DMASYNC_PREWRITE;
662
663 bus_dmamap_sync(dpt->buffer_dmat, dccb->dmamap, op);
664
665 } else {
666 dccb->eata_ccb.cp_dataDMA = 0;
667 dccb->eata_ccb.cp_datalen = 0;
668 }
669
670 s = splcam();
671
672 /*
673 * Last time we need to check if this CCB needs to
674 * be aborted.
675 */
676 if (ccb->ccb_h.status != CAM_REQ_INPROG) {
677 if (nseg != 0)
678 bus_dmamap_unload(dpt->buffer_dmat, dccb->dmamap);
679 dptfreeccb(dpt, dccb);
680 xpt_done(ccb);
681 splx(s);
682 return;
683 }
684
685 dccb->state |= DCCB_ACTIVE;
686 ccb->ccb_h.status |= CAM_SIM_QUEUED;
687 LIST_INSERT_HEAD(&dpt->pending_ccb_list, &ccb->ccb_h, sim_links.le);
688 ccb->ccb_h.timeout_ch =
689 timeout(dpttimeout, (caddr_t)dccb,
690 (ccb->ccb_h.timeout * hz) / 1000);
691 if (dpt_send_eata_command(dpt, &dccb->eata_ccb,
692 dccb->eata_ccb.cp_busaddr,
693 EATA_CMD_DMA_SEND_CP, 0, 0, 0, 0) != 0) {
694 ccb->ccb_h.status = CAM_NO_HBA; /* HBA dead or just busy?? */
695 if (nseg != 0)
696 bus_dmamap_unload(dpt->buffer_dmat, dccb->dmamap);
697 dptfreeccb(dpt, dccb);
698 xpt_done(ccb);
699 }
700
701 splx(s);
702}
703
704static void
705dpt_action(struct cam_sim *sim, union ccb *ccb)
706{
707 struct dpt_softc *dpt;
708
709 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("dpt_action\n"));
710
711 dpt = (struct dpt_softc *)cam_sim_softc(sim);
712
713 if ((dpt->state & DPT_HA_SHUTDOWN_ACTIVE) != 0) {
714 xpt_print_path(ccb->ccb_h.path);
715 printf("controller is shutdown. Aborting CCB.\n");
716 ccb->ccb_h.status = CAM_NO_HBA;
717 xpt_done(ccb);
718 return;
719 }
720
721 switch (ccb->ccb_h.func_code) {
722 /* Common cases first */
723 case XPT_SCSI_IO: /* Execute the requested I/O operation */
724 {
725 struct ccb_scsiio *csio;
726 struct ccb_hdr *ccbh;
727 struct dpt_ccb *dccb;
728 struct eata_ccb *eccb;
729
730 csio = &ccb->csio;
731 ccbh = &ccb->ccb_h;
732 /* Max CDB length is 12 bytes */
733 if (csio->cdb_len > 12) {
734 ccb->ccb_h.status = CAM_REQ_INVALID;
735 xpt_done(ccb);
736 return;
737 }
738 if ((dccb = dptgetccb(dpt)) == NULL) {
739 int s;
740
741 s = splcam();
742 dpt->resource_shortage = 1;
743 splx(s);
744 xpt_freeze_simq(sim, /*count*/1);
745 ccb->ccb_h.status = CAM_REQUEUE_REQ;
746 xpt_done(ccb);
747 return;
748 }
749 eccb = &dccb->eata_ccb;
750
751 /* Link dccb and ccb so we can find one from the other */
752 dccb->ccb = ccb;
753 ccb->ccb_h.ccb_dccb_ptr = dccb;
754 ccb->ccb_h.ccb_dpt_ptr = dpt;
755
756 /*
757 * Explicitly set all flags so that the compiler can
758 * be smart about setting them.
759 */
760 eccb->SCSI_Reset = 0;
761 eccb->HBA_Init = 0;
762 eccb->Auto_Req_Sen = (ccb->ccb_h.flags & CAM_DIS_AUTOSENSE)
763 ? 0 : 1;
764 eccb->scatter = 0;
765 eccb->Quick = 0;
766 eccb->Interpret =
767 ccb->ccb_h.target_id == dpt->hostid[cam_sim_bus(sim)]
768 ? 1 : 0;
769 eccb->DataOut = (ccb->ccb_h.flags & CAM_DIR_OUT) ? 1 : 0;
770 eccb->DataIn = (ccb->ccb_h.flags & CAM_DIR_IN) ? 1 : 0;
771 eccb->reqlen = csio->sense_len;
772 eccb->cp_id = ccb->ccb_h.target_id;
773 eccb->cp_channel = cam_sim_bus(sim);
774 eccb->cp_LUN = ccb->ccb_h.target_lun;
775 eccb->cp_luntar = 0;
776 eccb->cp_dispri = (ccb->ccb_h.flags & CAM_DIS_DISCONNECT)
777 ? 0 : 1;
778 eccb->cp_identify = 1;
779
780 if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0
781 && csio->tag_action != CAM_TAG_ACTION_NONE) {
782 eccb->cp_msg[0] = csio->tag_action;
783 eccb->cp_msg[1] = dccb->tag;
784 } else {
785 eccb->cp_msg[0] = 0;
786 eccb->cp_msg[1] = 0;
787 }
788 eccb->cp_msg[2] = 0;
789
790 if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
791 if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
792 bcopy(csio->cdb_io.cdb_ptr,
793 eccb->cp_cdb, csio->cdb_len);
794 } else {
795 /* I guess I could map it in... */
796 ccb->ccb_h.status = CAM_REQ_INVALID;
797 dptfreeccb(dpt, dccb);
798 xpt_done(ccb);
799 return;
800 }
801 } else {
802 bcopy(csio->cdb_io.cdb_bytes,
803 eccb->cp_cdb, csio->cdb_len);
804 }
805 /*
806 * If we have any data to send with this command,
807 * map it into bus space.
808 */
809 /* Only use S/G if there is a transfer */
810 if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
811 if ((ccbh->flags & CAM_SCATTER_VALID) == 0) {
812 /*
813 * We've been given a pointer
814 * to a single buffer.
815 */
816 if ((ccbh->flags & CAM_DATA_PHYS) == 0) {
817 int s;
818 int error;
819
820 s = splsoftvm();
821 error =
822 bus_dmamap_load(dpt->buffer_dmat,
823 dccb->dmamap,
824 csio->data_ptr,
825 csio->dxfer_len,
826 dptexecuteccb,
827 dccb, /*flags*/0);
828 if (error == EINPROGRESS) {
829 /*
830 * So as to maintain ordering,
831 * freeze the controller queue
832 * until our mapping is
833 * returned.
834 */
835 xpt_freeze_simq(sim, 1);
836 dccb->state |= CAM_RELEASE_SIMQ;
837 }
838 splx(s);
839 } else {
840 struct bus_dma_segment seg;
841
842 /* Pointer to physical buffer */
843 seg.ds_addr =
844 (bus_addr_t)csio->data_ptr;
845 seg.ds_len = csio->dxfer_len;
846 dptexecuteccb(dccb, &seg, 1, 0);
847 }
848 } else {
849 struct bus_dma_segment *segs;
850
851 if ((ccbh->flags & CAM_DATA_PHYS) != 0)
852 panic("dpt_action - Physical "
853 "segment pointers "
854 "unsupported");
855
856 if ((ccbh->flags&CAM_SG_LIST_PHYS)==0)
857 panic("dpt_action - Virtual "
858 "segment addresses "
859 "unsupported");
860
861 /* Just use the segments provided */
862 segs = (struct bus_dma_segment *)csio->data_ptr;
863 dptexecuteccb(dccb, segs, csio->sglist_cnt, 0);
864 }
865 } else {
866 /*
867 * XXX JGibbs.
868 * Does it want them both on or both off?
869 * CAM_DIR_NONE is both on, so this code can
870 * be removed if this is also what the DPT
871 * exptects.
872 */
873 eccb->DataOut = 0;
874 eccb->DataIn = 0;
875 dptexecuteccb(dccb, NULL, 0, 0);
876 }
877 break;
878 }
879 case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
880 case XPT_ABORT: /* Abort the specified CCB */
881 /* XXX Implement */
882 ccb->ccb_h.status = CAM_REQ_INVALID;
883 xpt_done(ccb);
884 break;
885 case XPT_SET_TRAN_SETTINGS:
886 {
887 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
888 xpt_done(ccb);
889 break;
890 }
891 case XPT_GET_TRAN_SETTINGS:
892 /* Get default/user set transfer settings for the target */
893 {
894 struct ccb_trans_settings *cts;
895 u_int target_mask;
896
897 cts = &ccb->cts;
898 target_mask = 0x01 << ccb->ccb_h.target_id;
899 if ((cts->flags & CCB_TRANS_USER_SETTINGS) != 0) {
900 cts->flags = CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB;
901 cts->bus_width = (dpt->max_id > 7)
902 ? MSG_EXT_WDTR_BUS_8_BIT
903 : MSG_EXT_WDTR_BUS_16_BIT;
904 cts->sync_period = 25; /* 10MHz */
905
906 if (cts->sync_period != 0)
907 cts->sync_offset = 15;
908
909 cts->valid = CCB_TRANS_SYNC_RATE_VALID
910 | CCB_TRANS_SYNC_OFFSET_VALID
911 | CCB_TRANS_BUS_WIDTH_VALID
912 | CCB_TRANS_DISC_VALID
913 | CCB_TRANS_TQ_VALID;
914 ccb->ccb_h.status = CAM_REQ_CMP;
915 } else {
916 ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
917 }
918 xpt_done(ccb);
919 break;
920 }
921 case XPT_CALC_GEOMETRY:
922 {
923 struct ccb_calc_geometry *ccg;
924 u_int32_t size_mb;
925 u_int32_t secs_per_cylinder;
926 int extended;
927
928 /*
929 * XXX Use Adaptec translation until I find out how to
930 * get this information from the card.
931 */
932 ccg = &ccb->ccg;
933 size_mb = ccg->volume_size
934 / ((1024L * 1024L) / ccg->block_size);
935 extended = 1;
936
937 if (size_mb > 1024 && extended) {
938 ccg->heads = 255;
939 ccg->secs_per_track = 63;
940 } else {
941 ccg->heads = 64;
942 ccg->secs_per_track = 32;
943 }
944 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
945 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
946 ccb->ccb_h.status = CAM_REQ_CMP;
947 xpt_done(ccb);
948 break;
949 }
950 case XPT_RESET_BUS: /* Reset the specified SCSI bus */
951 {
952 /* XXX Implement */
953 ccb->ccb_h.status = CAM_REQ_CMP;
954 xpt_done(ccb);
955 break;
956 }
957 case XPT_TERM_IO: /* Terminate the I/O process */
958 /* XXX Implement */
959 ccb->ccb_h.status = CAM_REQ_INVALID;
960 xpt_done(ccb);
961 break;
962 case XPT_PATH_INQ: /* Path routing inquiry */
963 {
964 struct ccb_pathinq *cpi = &ccb->cpi;
965
966 cpi->version_num = 1;
967 cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
968 if (dpt->max_id > 7)
969 cpi->hba_inquiry |= PI_WIDE_16;
970 cpi->target_sprt = 0;
971 cpi->hba_misc = 0;
972 cpi->hba_eng_cnt = 0;
973 cpi->max_target = dpt->max_id;
974 cpi->max_lun = dpt->max_lun;
975 cpi->initiator_id = dpt->hostid[cam_sim_bus(sim)];
976 cpi->bus_id = cam_sim_bus(sim);
977 cpi->base_transfer_speed = 3300;
978 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
979 strncpy(cpi->hba_vid, "DPT", HBA_IDLEN);
980 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
981 cpi->unit_number = cam_sim_unit(sim);
982 cpi->ccb_h.status = CAM_REQ_CMP;
983 xpt_done(ccb);
984 break;
985 }
986 default:
987 ccb->ccb_h.status = CAM_REQ_INVALID;
988 xpt_done(ccb);
989 break;
990 }
991}
992
993/*
994 * This routine will try to send an EATA command to the DPT HBA.
995 * It will, by default, try 20,000 times, waiting 50us between tries.
996 * It returns 0 on success and 1 on failure.
997 * It is assumed to be called at splcam().
998 */
999static int
1000dpt_send_eata_command(dpt_softc_t *dpt, eata_ccb_t *cmd_block,
1001 u_int32_t cmd_busaddr, u_int command, u_int retries,
1002 u_int ifc, u_int code, u_int code2)
1003{
1004 u_int loop;
1005
1006 if (!retries)
1007 retries = 20000;
1008
1009 /*
1010 * I hate this polling nonsense. Wish there was a way to tell the DPT
1011 * to go get commands at its own pace, or to interrupt when ready.
1012 * In the mean time we will measure how many itterations it really
1013 * takes.
1014 */
1015 for (loop = 0; loop < retries; loop++) {
1016 if ((dpt_inb(dpt, HA_RAUXSTAT) & HA_ABUSY) == 0)
1017 break;
1018 else
1019 DELAY(50);
1020 }
1021
1022 if (loop < retries) {
1023#ifdef DPT_MEASURE_PERFORMANCE
1024 if (loop > dpt->performance.max_eata_tries)
1025 dpt->performance.max_eata_tries = loop;
1026
1027 if (loop < dpt->performance.min_eata_tries)
1028 dpt->performance.min_eata_tries = loop;
1029#endif
1030 } else {
1031#ifdef DPT_MEASURE_PERFORMANCE
1032 ++dpt->performance.command_too_busy;
1033#endif
1034 return (1);
1035 }
1036
1037 /* The controller is alive, advance the wedge timer */
1038#ifdef DPT_RESET_HBA
1039 dpt->last_contact = microtime_now;
1040#endif
1041
1042 if (cmd_block == NULL)
1043 cmd_busaddr = 0;
1044#if (BYTE_ORDER == BIG_ENDIAN)
1045 else {
1046 cmd_busaddr = ((cmd_busaddr >> 24) & 0xFF)
1047 | ((cmd_busaddr >> 16) & 0xFF)
1048 | ((cmd_busaddr >> 8) & 0xFF)
1049 | (cmd_busaddr & 0xFF);
1050 }
1051#endif
1052 /* And now the address */
1053 dpt_outl(dpt, HA_WDMAADDR, cmd_busaddr);
1054
1055 if (command == EATA_CMD_IMMEDIATE) {
1056 if (cmd_block == NULL) {
1057 dpt_outb(dpt, HA_WCODE2, code2);
1058 dpt_outb(dpt, HA_WCODE, code);
1059 }
1060 dpt_outb(dpt, HA_WIFC, ifc);
1061 }
1062 dpt_outb(dpt, HA_WCOMMAND, command);
1063
1064 return (0);
1065}
1066
1067
1068/* ==================== Exported Function definitions =======================*/
1069struct dpt_softc *
1070dpt_alloc(u_int unit, bus_space_tag_t tag, bus_space_handle_t bsh)
1071{
1072 struct dpt_softc *dpt;
1073 int i;
1074
1075 dpt = (struct dpt_softc *)malloc(sizeof(*dpt), M_DEVBUF, M_NOWAIT);
1076 if (dpt == NULL) {
1077 printf("dpt%d: Unable to allocate softc\n", dpt->unit);
1078 return (NULL);
1079 }
1080
1081 bzero(dpt, sizeof(dpt_softc_t));
1082 dpt->tag = tag;
1083 dpt->bsh = bsh;
1084 dpt->unit = unit;
1085 SLIST_INIT(&dpt->free_dccb_list);
1086 LIST_INIT(&dpt->pending_ccb_list);
1087 TAILQ_INSERT_TAIL(&dpt_softcs, dpt, links);
1088 for (i = 0; i < MAX_CHANNELS; i++)
1089 dpt->resetlevel[i] = DPT_HA_OK;
1090
1091#ifdef DPT_MEASURE_PERFORMANCE
1092 dpt_reset_performance(dpt);
1093#endif /* DPT_MEASURE_PERFORMANCE */
1094 return (dpt);
1095}
1096
1097void
1098dpt_free(struct dpt_softc *dpt)
1099{
1100 switch (dpt->init_level) {
1101 default:
1102 case 5:
1103 bus_dmamap_unload(dpt->dccb_dmat, dpt->dccb_dmamap);
1104 case 4:
1105 bus_dmamem_free(dpt->dccb_dmat, dpt->dpt_dccbs,
1106 dpt->dccb_dmamap);
1107 bus_dmamap_destroy(dpt->dccb_dmat, dpt->dccb_dmamap);
1108 case 3:
1109 bus_dma_tag_destroy(dpt->dccb_dmat);
1110 case 2:
1111 bus_dma_tag_destroy(dpt->buffer_dmat);
1112 case 1:
1113 {
1114 struct sg_map_node *sg_map;
1115
1116 while ((sg_map = SLIST_FIRST(&dpt->sg_maps)) != NULL) {
1117 SLIST_REMOVE_HEAD(&dpt->sg_maps, links);
1118 bus_dmamap_unload(dpt->sg_dmat,
1119 sg_map->sg_dmamap);
1120 bus_dmamem_free(dpt->sg_dmat, sg_map->sg_vaddr,
1121 sg_map->sg_dmamap);
1122 free(sg_map, M_DEVBUF);
1123 }
1124 bus_dma_tag_destroy(dpt->sg_dmat);
1125 }
1126 case 0:
1127 break;
1128 }
1129 TAILQ_REMOVE(&dpt_softcs, dpt, links);
1130 free(dpt, M_DEVBUF);
1131}
1132
1133static u_int8_t string_sizes[] =
1134{
1135 sizeof(((dpt_inq_t*)NULL)->vendor),
1136 sizeof(((dpt_inq_t*)NULL)->modelNum),
1137 sizeof(((dpt_inq_t*)NULL)->firmware),
1138 sizeof(((dpt_inq_t*)NULL)->protocol),
1139};
1140
1141int
1142dpt_init(struct dpt_softc *dpt)
1143{
1144 dpt_conf_t conf;
1145 struct sg_map_node *sg_map;
1146 dpt_ccb_t *dccb;
1147 u_int8_t *strp;
1148 int index;
1149 int i;
1150 int retval;
1151
1152 dpt->init_level = 0;
1153 SLIST_INIT(&dpt->sg_maps);
1154
1155#ifdef DPT_RESET_BOARD
1156 printf("dpt%d: resetting HBA\n", dpt->unit);
1157 dpt_outb(dpt, HA_WCOMMAND, EATA_CMD_RESET);
1158 DELAY(750000);
1159 /* XXX Shouldn't we poll a status register or something??? */
1160#endif
1161 /* DMA tag for our S/G structures. We allocate in page sized chunks */
1162 if (bus_dma_tag_create(dpt->parent_dmat, /*alignment*/1, /*boundary*/0,
1163 /*lowaddr*/BUS_SPACE_MAXADDR,
1164 /*highaddr*/BUS_SPACE_MAXADDR,
1165 /*filter*/NULL, /*filterarg*/NULL,
1166 PAGE_SIZE, /*nsegments*/1,
1167 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
1168 /*flags*/0, &dpt->sg_dmat) != 0) {
1169 goto error_exit;
1170 }
1171
1172 dpt->init_level++;
1173
1174 /*
1175 * We allocate our DPT ccbs as a contiguous array of bus dma'able
1176 * memory. To get the allocation size, we need to know how many
1177 * ccbs the card supports. This requires a ccb. We solve this
1178 * chicken and egg problem by allocating some re-usable S/G space
1179 * up front, and treating it as our status packet, CCB, and target
1180 * memory space for these commands.
1181 */
1182 sg_map = dptallocsgmap(dpt);
1183 if (sg_map == NULL)
1184 goto error_exit;
1185
1186 dpt->sp = (volatile dpt_sp_t *)sg_map->sg_vaddr;
1187 dccb = (struct dpt_ccb *)&dpt->sp[1];
1188 bzero(dccb, sizeof(*dccb));
1189 dpt->sp_physaddr = sg_map->sg_physaddr;
1190 dccb->eata_ccb.cp_dataDMA =
1191 htonl(sg_map->sg_physaddr + sizeof(dpt_sp_t) + sizeof(*dccb));
1192 dccb->eata_ccb.cp_busaddr = ~0;
1193 dccb->eata_ccb.cp_statDMA = htonl(dpt->sp_physaddr);
1194 dccb->eata_ccb.cp_reqDMA = htonl(dpt->sp_physaddr + sizeof(*dccb)
1195 + offsetof(struct dpt_ccb, sense_data));
1196
1197 /* Okay. Fetch our config */
1198 bzero(&dccb[1], sizeof(conf)); /* data area */
1199 retval = dpt_get_conf(dpt, dccb, sg_map->sg_physaddr + sizeof(dpt_sp_t),
1200 sizeof(conf), 0xc1, 7, 1);
1201
1202 if (retval != 0) {
1203 printf("dpt%d: Failed to get board configuration\n", dpt->unit);
1204 return (retval);
1205 }
1206 bcopy(&dccb[1], &conf, sizeof(conf));
1207
1208 bzero(&dccb[1], sizeof(dpt->board_data));
1209 retval = dpt_get_conf(dpt, dccb, sg_map->sg_physaddr + sizeof(dpt_sp_t),
1210 sizeof(dpt->board_data), 0, conf.scsi_id0, 0);
1211 if (retval != 0) {
1212 printf("dpt%d: Failed to get inquiry information\n", dpt->unit);
1213 return (retval);
1214 }
1215 bcopy(&dccb[1], &dpt->board_data, sizeof(dpt->board_data));
1216
1217 dpt_detect_cache(dpt, dccb, sg_map->sg_physaddr + sizeof(dpt_sp_t),
1218 (u_int8_t *)&dccb[1]);
1219
1220 switch (ntohl(conf.splen)) {
1221 case DPT_EATA_REVA:
1222 dpt->EATA_revision = 'a';
1223 break;
1224 case DPT_EATA_REVB:
1225 dpt->EATA_revision = 'b';
1226 break;
1227 case DPT_EATA_REVC:
1228 dpt->EATA_revision = 'c';
1229 break;
1230 case DPT_EATA_REVZ:
1231 dpt->EATA_revision = 'z';
1232 break;
1233 default:
1234 dpt->EATA_revision = '?';
1235 }
1236
1237 dpt->max_id = conf.MAX_ID;
1238 dpt->max_lun = conf.MAX_LUN;
1239 dpt->irq = conf.IRQ;
1240 dpt->dma_channel = (8 - conf.DMA_channel) & 7;
1241 dpt->channels = conf.MAX_CHAN + 1;
1242 dpt->state |= DPT_HA_OK;
1243 if (conf.SECOND)
1244 dpt->primary = FALSE;
1245 else
1246 dpt->primary = TRUE;
1247
1248 dpt->more_support = conf.MORE_support;
1249
1250 if (strncmp(dpt->board_data.firmware, "07G0", 4) >= 0)
1251 dpt->immediate_support = 1;
1252 else
1253 dpt->immediate_support = 0;
1254
1255 dpt->broken_INQUIRY = FALSE;
1256
1257 dpt->cplen = ntohl(conf.cplen);
1258 dpt->cppadlen = ntohs(conf.cppadlen);
1259 dpt->max_dccbs = ntohs(conf.queuesiz);
1260
1261 if (dpt->max_dccbs > 256) {
1262 printf("dpt%d: Max CCBs reduced from %d to "
1263 "256 due to tag algorithm\n", dpt->unit, dpt->max_dccbs);
1264 dpt->max_dccbs = 256;
1265 }
1266
1267 dpt->hostid[0] = conf.scsi_id0;
1268 dpt->hostid[1] = conf.scsi_id1;
1269 dpt->hostid[2] = conf.scsi_id2;
1270
1271 if (conf.SG_64K)
1272 dpt->sgsize = 8192;
1273 else
1274 dpt->sgsize = ntohs(conf.SGsiz);
1275
1276 /* We can only get 64k buffers, so don't bother to waste space. */
1277 if (dpt->sgsize < 17 || dpt->sgsize > 32)
1278 dpt->sgsize = 32;
1279
1280 if (dpt->sgsize > dpt_max_segs)
1281 dpt->sgsize = dpt_max_segs;
1282
1283 /* DMA tag for mapping buffers into device visible space. */
1284 if (bus_dma_tag_create(dpt->parent_dmat, /*alignment*/1, /*boundary*/0,
1285 /*lowaddr*/BUS_SPACE_MAXADDR,
1286 /*highaddr*/BUS_SPACE_MAXADDR,
1287 /*filter*/NULL, /*filterarg*/NULL,
1288 /*maxsize*/MAXBSIZE, /*nsegments*/dpt->sgsize,
1289 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
1290 /*flags*/BUS_DMA_ALLOCNOW,
1291 &dpt->buffer_dmat) != 0) {
1292 goto error_exit;
1293 }
1294
1295 dpt->init_level++;
1296
1297 /* DMA tag for our ccb structures and interrupt status packet */
1298 if (bus_dma_tag_create(dpt->parent_dmat, /*alignment*/1, /*boundary*/0,
1299 /*lowaddr*/BUS_SPACE_MAXADDR,
1300 /*highaddr*/BUS_SPACE_MAXADDR,
1301 /*filter*/NULL, /*filterarg*/NULL,
1302 (dpt->max_dccbs * sizeof(struct dpt_ccb))
1303 + sizeof(dpt_sp_t),
1304 /*nsegments*/1,
1305 /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
1306 /*flags*/0, &dpt->dccb_dmat) != 0) {
1307 goto error_exit;
1308 }
1309
1310 dpt->init_level++;
1311
1312 /* Allocation for our ccbs and interrupt status packet */
1313 if (bus_dmamem_alloc(dpt->dccb_dmat, (void **)&dpt->dpt_dccbs,
1314 BUS_DMA_NOWAIT, &dpt->dccb_dmamap) != 0) {
1315 goto error_exit;
1316 }
1317
1318 dpt->init_level++;
1319
1320 /* And permanently map them */
1321 bus_dmamap_load(dpt->dccb_dmat, dpt->dccb_dmamap,
1322 dpt->dpt_dccbs,
1323 (dpt->max_dccbs * sizeof(struct dpt_ccb))
1324 + sizeof(dpt_sp_t),
1325 dptmapmem, &dpt->dpt_ccb_busbase, /*flags*/0);
1326
1327 /* Clear them out. */
1328 bzero(dpt->dpt_dccbs,
1329 (dpt->max_dccbs * sizeof(struct dpt_ccb)) + sizeof(dpt_sp_t));
1330
1331 dpt->dpt_ccb_busend = dpt->dpt_ccb_busbase;
1332
1333 dpt->sp = (dpt_sp_t*)&dpt->dpt_dccbs[dpt->max_dccbs];
1334 dpt->sp_physaddr = dpt->dpt_ccb_busbase
1335 + (dpt->max_dccbs * sizeof(dpt_ccb_t));
1336 dpt->init_level++;
1337
1338 /* Allocate our first batch of ccbs */
1339 if (dptallocccbs(dpt) == 0)
1340 return (2);
1341
1342 /* Prepare for Target Mode */
1343 dpt->target_mode_enabled = 1;
1344
1345 /* Nuke excess spaces from inquiry information */
1346 strp = dpt->board_data.vendor;
1347 for (i = 0; i < sizeof(string_sizes); i++) {
1348 index = string_sizes[i] - 1;
1349 while (index && (strp[index] == ' '))
1350 strp[index--] = '\0';
1351 strp += string_sizes[i];
1352 }
1353
1354 printf("dpt%d: %.8s %.16s FW Rev. %.4s, ",
1355 dpt->unit, dpt->board_data.vendor,
1356 dpt->board_data.modelNum, dpt->board_data.firmware);
1357
1358 printf("%d channel%s, ", dpt->channels, dpt->channels > 1 ? "s" : "");
1359
1360 if (dpt->cache_type != DPT_NO_CACHE
1361 && dpt->cache_size != 0) {
1362 printf("%s Cache, ",
1363 dpt->cache_type == DPT_CACHE_WRITETHROUGH
1364 ? "Write-Through" : "Write-Back");
1365 }
1366
1367 printf("%d CCBs\n", dpt->max_dccbs);
1368 return (0);
1369
1370error_exit:
1371 return (1);
1372}
1373
1374int
1375dpt_attach(dpt_softc_t *dpt)
1376{
1377 struct cam_devq *devq;
1378 int i;
1379
1380 /*
1381 * Create the device queue for our SIM.
1382 */
1383 devq = cam_simq_alloc(dpt->max_dccbs);
1384 if (devq == NULL)
1385 return (0);
1386
1387 for (i = 0; i < dpt->channels; i++) {
1388 /*
1389 * Construct our SIM entry
1390 */
1391 dpt->sims[i] = cam_sim_alloc(dpt_action, dpt_poll, "dpt",
1392 dpt, dpt->unit, /*untagged*/2,
1393 /*tagged*/dpt->max_dccbs, devq);
1394 if (xpt_bus_register(dpt->sims[i], i) != CAM_SUCCESS) {
1395 cam_sim_free(dpt->sims[i], /*free_devq*/i == 0);
1396 break;
1397 }
1398
1399 if (xpt_create_path(&dpt->paths[i], /*periph*/NULL,
1400 cam_sim_path(dpt->sims[i]),
1401 CAM_TARGET_WILDCARD,
1402 CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1403 xpt_bus_deregister(cam_sim_path(dpt->sims[i]));
1404 cam_sim_free(dpt->sims[i], /*free_devq*/i == 0);
1405 break;
1406 }
1407
1408 }
1409 if (i > 0)
1410 at_shutdown(dptshutdown, dpt, SHUTDOWN_FINAL);
1410 EVENTHANDLER_REGISTER(shutdown_final, dptshutdown,
1411 dpt, SHUTDOWN_PRI_DEFAULT);
1411 return (i);
1412}
1413
1414
1415/*
1416 * This is the interrupt handler for the DPT driver.
1417 */
1418void
1419dpt_intr(void *arg)
1420{
1421 dpt_softc_t *dpt;
1422 dpt_ccb_t *dccb;
1423 union ccb *ccb;
1424 u_int status;
1425 u_int aux_status;
1426 u_int hba_stat;
1427 u_int scsi_stat;
1428 u_int32_t residue_len; /* Number of bytes not transferred */
1429
1430 dpt = (dpt_softc_t *)arg;
1431
1432 /* First order of business is to check if this interrupt is for us */
1433 while (((aux_status = dpt_inb(dpt, HA_RAUXSTAT)) & HA_AIRQ) != 0) {
1434
1435 /*
1436 * What we want to do now, is to capture the status, all of it,
1437 * move it where it belongs, wake up whoever sleeps waiting to
1438 * process this result, and get out of here.
1439 */
1440 if (dpt->sp->ccb_busaddr < dpt->dpt_ccb_busbase
1441 || dpt->sp->ccb_busaddr >= dpt->dpt_ccb_busend) {
1442 printf("Encountered bogus status packet\n");
1443 status = dpt_inb(dpt, HA_RSTATUS);
1444 return;
1445 }
1446
1447 dccb = dptccbptov(dpt, dpt->sp->ccb_busaddr);
1448
1449 dpt->sp->ccb_busaddr = ~0;
1450
1451 /* Ignore status packets with EOC not set */
1452 if (dpt->sp->EOC == 0) {
1453 printf("dpt%d ERROR: Request %d recieved with "
1454 "clear EOC.\n Marking as LOST.\n",
1455 dpt->unit, dccb->transaction_id);
1456
1457#ifdef DPT_HANDLE_TIMEOUTS
1458 dccb->state |= DPT_CCB_STATE_MARKED_LOST;
1459#endif
1460 /* This CLEARS the interrupt! */
1461 status = dpt_inb(dpt, HA_RSTATUS);
1462 continue;
1463 }
1464 dpt->sp->EOC = 0;
1465
1466 /*
1467 * Double buffer the status information so the hardware can
1468 * work on updating the status packet while we decifer the
1469 * one we were just interrupted for.
1470 * According to Mark Salyzyn, we only need few pieces of it.
1471 */
1472 hba_stat = dpt->sp->hba_stat;
1473 scsi_stat = dpt->sp->scsi_stat;
1474 residue_len = dpt->sp->residue_len;
1475
1476 /* Clear interrupts, check for error */
1477 if ((status = dpt_inb(dpt, HA_RSTATUS)) & HA_SERROR) {
1478 /*
1479 * Error Condition. Check for magic cookie. Exit
1480 * this test on earliest sign of non-reset condition
1481 */
1482
1483 /* Check that this is not a board reset interrupt */
1484 if (dpt_just_reset(dpt)) {
1485 printf("dpt%d: HBA rebooted.\n"
1486 " All transactions should be "
1487 "resubmitted\n",
1488 dpt->unit);
1489
1490 printf("dpt%d: >>---->> This is incomplete, "
1491 "fix me.... <<----<<", dpt->unit);
1492 panic("DPT Rebooted");
1493
1494 }
1495 }
1496 /* Process CCB */
1497 ccb = dccb->ccb;
1498 untimeout(dpttimeout, dccb, ccb->ccb_h.timeout_ch);
1499 if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1500 bus_dmasync_op_t op;
1501
1502 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
1503 op = BUS_DMASYNC_POSTREAD;
1504 else
1505 op = BUS_DMASYNC_POSTWRITE;
1506 bus_dmamap_sync(dpt->buffer_dmat, dccb->dmamap, op);
1507 bus_dmamap_unload(dpt->buffer_dmat, dccb->dmamap);
1508 }
1509
1510 /* Common Case inline... */
1511 if (hba_stat == HA_NO_ERROR) {
1512 ccb->csio.scsi_status = scsi_stat;
1513 ccb->ccb_h.status = 0;
1514 switch (scsi_stat) {
1515 case SCSI_STATUS_OK:
1516 ccb->ccb_h.status |= CAM_REQ_CMP;
1517 break;
1518 case SCSI_STATUS_CHECK_COND:
1519 case SCSI_STATUS_CMD_TERMINATED:
1520 bcopy(&dccb->sense_data, &ccb->csio.sense_data,
1521 ccb->csio.sense_len);
1522 ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1523 /* FALLTHROUGH */
1524 default:
1525 ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
1526 /* XXX Freeze DevQ */
1527 break;
1528 }
1529 ccb->csio.resid = residue_len;
1530 dptfreeccb(dpt, dccb);
1531 xpt_done(ccb);
1532 } else {
1533 dptprocesserror(dpt, dccb, ccb, hba_stat, scsi_stat,
1534 residue_len);
1535 }
1536 }
1537}
1538
1539static void
1540dptprocesserror(dpt_softc_t *dpt, dpt_ccb_t *dccb, union ccb *ccb,
1541 u_int hba_stat, u_int scsi_stat, u_int32_t resid)
1542{
1543 ccb->csio.resid = resid;
1544 switch (hba_stat) {
1545 case HA_ERR_SEL_TO:
1546 ccb->ccb_h.status = CAM_SEL_TIMEOUT;
1547 break;
1548 case HA_ERR_CMD_TO:
1549 ccb->ccb_h.status = CAM_CMD_TIMEOUT;
1550 break;
1551 case HA_SCSIBUS_RESET:
1552 case HA_HBA_POWER_UP: /* Similar effect to a bus reset??? */
1553 ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
1554 break;
1555 case HA_CP_ABORTED:
1556 case HA_CP_RESET: /* XXX ??? */
1557 case HA_CP_ABORT_NA: /* XXX ??? */
1558 case HA_CP_RESET_NA: /* XXX ??? */
1559 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
1560 ccb->ccb_h.status = CAM_REQ_ABORTED;
1561 break;
1562 case HA_PCI_PARITY:
1563 case HA_PCI_MABORT:
1564 case HA_PCI_TABORT:
1565 case HA_PCI_STABORT:
1566 case HA_BUS_PARITY:
1567 case HA_PARITY_ERR:
1568 case HA_ECC_ERR:
1569 ccb->ccb_h.status = CAM_UNCOR_PARITY;
1570 break;
1571 case HA_UNX_MSGRJCT:
1572 ccb->ccb_h.status = CAM_MSG_REJECT_REC;
1573 break;
1574 case HA_UNX_BUSPHASE:
1575 ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
1576 break;
1577 case HA_UNX_BUS_FREE:
1578 ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
1579 break;
1580 case HA_SCSI_HUNG:
1581 case HA_RESET_STUCK:
1582 /*
1583 * Dead??? Can the controller get unstuck
1584 * from these conditions
1585 */
1586 ccb->ccb_h.status = CAM_NO_HBA;
1587 break;
1588 case HA_RSENSE_FAIL:
1589 ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
1590 break;
1591 default:
1592 printf("dpt%d: Undocumented Error %x\n", dpt->unit, hba_stat);
1593 printf("Please mail this message to shimon@simon-shapiro.org\n");
1594 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1595 break;
1596 }
1597 dptfreeccb(dpt, dccb);
1598 xpt_done(ccb);
1599}
1600
1601static void
1602dpttimeout(void *arg)
1603{
1604 struct dpt_ccb *dccb;
1605 union ccb *ccb;
1606 struct dpt_softc *dpt;
1607 int s;
1608
1609 dccb = (struct dpt_ccb *)arg;
1610 ccb = dccb->ccb;
1611 dpt = (struct dpt_softc *)ccb->ccb_h.ccb_dpt_ptr;
1612 xpt_print_path(ccb->ccb_h.path);
1613 printf("CCB %p - timed out\n", (void *)dccb);
1614
1615 s = splcam();
1616
1617 /*
1618 * Try to clear any pending jobs. FreeBSD will loose interrupts,
1619 * leaving the controller suspended, and commands timed-out.
1620 * By calling the interrupt handler, any command thus stuck will be
1621 * completed.
1622 */
1623 dpt_intr(dpt);
1624
1625 if ((dccb->state & DCCB_ACTIVE) == 0) {
1626 xpt_print_path(ccb->ccb_h.path);
1627 printf("CCB %p - timed out CCB already completed\n",
1628 (void *)dccb);
1629 splx(s);
1630 return;
1631 }
1632
1633 /* Abort this particular command. Leave all others running */
1634 dpt_send_immediate(dpt, &dccb->eata_ccb, dccb->eata_ccb.cp_busaddr,
1635 /*retries*/20000, EATA_SPECIFIC_ABORT, 0, 0);
1636 ccb->ccb_h.status = CAM_CMD_TIMEOUT;
1637 splx(s);
1638}
1639
1640/*
1641 * Shutdown the controller and ensure that the cache is completely flushed.
1412 return (i);
1413}
1414
1415
1416/*
1417 * This is the interrupt handler for the DPT driver.
1418 */
1419void
1420dpt_intr(void *arg)
1421{
1422 dpt_softc_t *dpt;
1423 dpt_ccb_t *dccb;
1424 union ccb *ccb;
1425 u_int status;
1426 u_int aux_status;
1427 u_int hba_stat;
1428 u_int scsi_stat;
1429 u_int32_t residue_len; /* Number of bytes not transferred */
1430
1431 dpt = (dpt_softc_t *)arg;
1432
1433 /* First order of business is to check if this interrupt is for us */
1434 while (((aux_status = dpt_inb(dpt, HA_RAUXSTAT)) & HA_AIRQ) != 0) {
1435
1436 /*
1437 * What we want to do now, is to capture the status, all of it,
1438 * move it where it belongs, wake up whoever sleeps waiting to
1439 * process this result, and get out of here.
1440 */
1441 if (dpt->sp->ccb_busaddr < dpt->dpt_ccb_busbase
1442 || dpt->sp->ccb_busaddr >= dpt->dpt_ccb_busend) {
1443 printf("Encountered bogus status packet\n");
1444 status = dpt_inb(dpt, HA_RSTATUS);
1445 return;
1446 }
1447
1448 dccb = dptccbptov(dpt, dpt->sp->ccb_busaddr);
1449
1450 dpt->sp->ccb_busaddr = ~0;
1451
1452 /* Ignore status packets with EOC not set */
1453 if (dpt->sp->EOC == 0) {
1454 printf("dpt%d ERROR: Request %d recieved with "
1455 "clear EOC.\n Marking as LOST.\n",
1456 dpt->unit, dccb->transaction_id);
1457
1458#ifdef DPT_HANDLE_TIMEOUTS
1459 dccb->state |= DPT_CCB_STATE_MARKED_LOST;
1460#endif
1461 /* This CLEARS the interrupt! */
1462 status = dpt_inb(dpt, HA_RSTATUS);
1463 continue;
1464 }
1465 dpt->sp->EOC = 0;
1466
1467 /*
1468 * Double buffer the status information so the hardware can
1469 * work on updating the status packet while we decifer the
1470 * one we were just interrupted for.
1471 * According to Mark Salyzyn, we only need few pieces of it.
1472 */
1473 hba_stat = dpt->sp->hba_stat;
1474 scsi_stat = dpt->sp->scsi_stat;
1475 residue_len = dpt->sp->residue_len;
1476
1477 /* Clear interrupts, check for error */
1478 if ((status = dpt_inb(dpt, HA_RSTATUS)) & HA_SERROR) {
1479 /*
1480 * Error Condition. Check for magic cookie. Exit
1481 * this test on earliest sign of non-reset condition
1482 */
1483
1484 /* Check that this is not a board reset interrupt */
1485 if (dpt_just_reset(dpt)) {
1486 printf("dpt%d: HBA rebooted.\n"
1487 " All transactions should be "
1488 "resubmitted\n",
1489 dpt->unit);
1490
1491 printf("dpt%d: >>---->> This is incomplete, "
1492 "fix me.... <<----<<", dpt->unit);
1493 panic("DPT Rebooted");
1494
1495 }
1496 }
1497 /* Process CCB */
1498 ccb = dccb->ccb;
1499 untimeout(dpttimeout, dccb, ccb->ccb_h.timeout_ch);
1500 if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
1501 bus_dmasync_op_t op;
1502
1503 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
1504 op = BUS_DMASYNC_POSTREAD;
1505 else
1506 op = BUS_DMASYNC_POSTWRITE;
1507 bus_dmamap_sync(dpt->buffer_dmat, dccb->dmamap, op);
1508 bus_dmamap_unload(dpt->buffer_dmat, dccb->dmamap);
1509 }
1510
1511 /* Common Case inline... */
1512 if (hba_stat == HA_NO_ERROR) {
1513 ccb->csio.scsi_status = scsi_stat;
1514 ccb->ccb_h.status = 0;
1515 switch (scsi_stat) {
1516 case SCSI_STATUS_OK:
1517 ccb->ccb_h.status |= CAM_REQ_CMP;
1518 break;
1519 case SCSI_STATUS_CHECK_COND:
1520 case SCSI_STATUS_CMD_TERMINATED:
1521 bcopy(&dccb->sense_data, &ccb->csio.sense_data,
1522 ccb->csio.sense_len);
1523 ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
1524 /* FALLTHROUGH */
1525 default:
1526 ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
1527 /* XXX Freeze DevQ */
1528 break;
1529 }
1530 ccb->csio.resid = residue_len;
1531 dptfreeccb(dpt, dccb);
1532 xpt_done(ccb);
1533 } else {
1534 dptprocesserror(dpt, dccb, ccb, hba_stat, scsi_stat,
1535 residue_len);
1536 }
1537 }
1538}
1539
1540static void
1541dptprocesserror(dpt_softc_t *dpt, dpt_ccb_t *dccb, union ccb *ccb,
1542 u_int hba_stat, u_int scsi_stat, u_int32_t resid)
1543{
1544 ccb->csio.resid = resid;
1545 switch (hba_stat) {
1546 case HA_ERR_SEL_TO:
1547 ccb->ccb_h.status = CAM_SEL_TIMEOUT;
1548 break;
1549 case HA_ERR_CMD_TO:
1550 ccb->ccb_h.status = CAM_CMD_TIMEOUT;
1551 break;
1552 case HA_SCSIBUS_RESET:
1553 case HA_HBA_POWER_UP: /* Similar effect to a bus reset??? */
1554 ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
1555 break;
1556 case HA_CP_ABORTED:
1557 case HA_CP_RESET: /* XXX ??? */
1558 case HA_CP_ABORT_NA: /* XXX ??? */
1559 case HA_CP_RESET_NA: /* XXX ??? */
1560 if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
1561 ccb->ccb_h.status = CAM_REQ_ABORTED;
1562 break;
1563 case HA_PCI_PARITY:
1564 case HA_PCI_MABORT:
1565 case HA_PCI_TABORT:
1566 case HA_PCI_STABORT:
1567 case HA_BUS_PARITY:
1568 case HA_PARITY_ERR:
1569 case HA_ECC_ERR:
1570 ccb->ccb_h.status = CAM_UNCOR_PARITY;
1571 break;
1572 case HA_UNX_MSGRJCT:
1573 ccb->ccb_h.status = CAM_MSG_REJECT_REC;
1574 break;
1575 case HA_UNX_BUSPHASE:
1576 ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
1577 break;
1578 case HA_UNX_BUS_FREE:
1579 ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
1580 break;
1581 case HA_SCSI_HUNG:
1582 case HA_RESET_STUCK:
1583 /*
1584 * Dead??? Can the controller get unstuck
1585 * from these conditions
1586 */
1587 ccb->ccb_h.status = CAM_NO_HBA;
1588 break;
1589 case HA_RSENSE_FAIL:
1590 ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
1591 break;
1592 default:
1593 printf("dpt%d: Undocumented Error %x\n", dpt->unit, hba_stat);
1594 printf("Please mail this message to shimon@simon-shapiro.org\n");
1595 ccb->ccb_h.status = CAM_REQ_CMP_ERR;
1596 break;
1597 }
1598 dptfreeccb(dpt, dccb);
1599 xpt_done(ccb);
1600}
1601
1602static void
1603dpttimeout(void *arg)
1604{
1605 struct dpt_ccb *dccb;
1606 union ccb *ccb;
1607 struct dpt_softc *dpt;
1608 int s;
1609
1610 dccb = (struct dpt_ccb *)arg;
1611 ccb = dccb->ccb;
1612 dpt = (struct dpt_softc *)ccb->ccb_h.ccb_dpt_ptr;
1613 xpt_print_path(ccb->ccb_h.path);
1614 printf("CCB %p - timed out\n", (void *)dccb);
1615
1616 s = splcam();
1617
1618 /*
1619 * Try to clear any pending jobs. FreeBSD will loose interrupts,
1620 * leaving the controller suspended, and commands timed-out.
1621 * By calling the interrupt handler, any command thus stuck will be
1622 * completed.
1623 */
1624 dpt_intr(dpt);
1625
1626 if ((dccb->state & DCCB_ACTIVE) == 0) {
1627 xpt_print_path(ccb->ccb_h.path);
1628 printf("CCB %p - timed out CCB already completed\n",
1629 (void *)dccb);
1630 splx(s);
1631 return;
1632 }
1633
1634 /* Abort this particular command. Leave all others running */
1635 dpt_send_immediate(dpt, &dccb->eata_ccb, dccb->eata_ccb.cp_busaddr,
1636 /*retries*/20000, EATA_SPECIFIC_ABORT, 0, 0);
1637 ccb->ccb_h.status = CAM_CMD_TIMEOUT;
1638 splx(s);
1639}
1640
1641/*
1642 * Shutdown the controller and ensure that the cache is completely flushed.
1642 * Called via at_shutdown(9) after all disk access has completed.
1643 * Called from the shutdown_final event after all disk access has completed.
1643 */
1644static void
1644 */
1645static void
1645dptshutdown(int howto, void *arg)
1646dptshutdown(void *arg, int howto)
1646{
1647 dpt_softc_t *dpt;
1648
1649 dpt = (dpt_softc_t *)arg;
1650
1651 printf("dpt%d: Shutting down (mode %x) HBA. Please wait...\n",
1652 dpt->unit, howto);
1653
1654 /*
1655 * What we do for a shutdown, is give the DPT early power loss warning
1656 */
1657 dpt_send_immediate(dpt, NULL, 0, EATA_POWER_OFF_WARN, 0, 0, 0);
1658 DELAY(1000 * 1000 * 5);
1659 printf("dpt%d: Controller was warned of shutdown and is now "
1660 "disabled\n", dpt->unit);
1661}
1662
1663/*============================================================================*/
1664
1665#if 0
1666#ifdef DPT_RESET_HBA
1667
1668/*
1669** Function name : dpt_reset_hba
1670**
1671** Description : Reset the HBA and properly discard all pending work
1672** Input : Softc
1673** Output : Nothing
1674*/
1675static void
1676dpt_reset_hba(dpt_softc_t *dpt)
1677{
1678 eata_ccb_t *ccb;
1679 int ospl;
1680 dpt_ccb_t dccb, *dccbp;
1681 int result;
1682 struct scsi_xfer *xs;
1683
1684 /* Prepare a control block. The SCSI command part is immaterial */
1685 dccb.xs = NULL;
1686 dccb.flags = 0;
1687 dccb.state = DPT_CCB_STATE_NEW;
1688 dccb.std_callback = NULL;
1689 dccb.wrbuff_callback = NULL;
1690
1691 ccb = &dccb.eata_ccb;
1692 ccb->CP_OpCode = EATA_CMD_RESET;
1693 ccb->SCSI_Reset = 0;
1694 ccb->HBA_Init = 1;
1695 ccb->Auto_Req_Sen = 1;
1696 ccb->cp_id = 0; /* Should be ignored */
1697 ccb->DataIn = 1;
1698 ccb->DataOut = 0;
1699 ccb->Interpret = 1;
1700 ccb->reqlen = htonl(sizeof(struct scsi_sense_data));
1701 ccb->cp_statDMA = htonl(vtophys(&ccb->cp_statDMA));
1702 ccb->cp_reqDMA = htonl(vtophys(&ccb->cp_reqDMA));
1703 ccb->cp_viraddr = (u_int32_t) & ccb;
1704
1705 ccb->cp_msg[0] = HA_IDENTIFY_MSG | HA_DISCO_RECO;
1706 ccb->cp_scsi_cmd = 0; /* Should be ignored */
1707
1708 /* Lock up the submitted queue. We are very persistant here */
1709 ospl = splcam();
1710 while (dpt->queue_status & DPT_SUBMITTED_QUEUE_ACTIVE) {
1711 DELAY(100);
1712 }
1713
1714 dpt->queue_status |= DPT_SUBMITTED_QUEUE_ACTIVE;
1715 splx(ospl);
1716
1717 /* Send the RESET message */
1718 if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb,
1719 EATA_CMD_RESET, 0, 0, 0, 0)) != 0) {
1720 printf("dpt%d: Failed to send the RESET message.\n"
1721 " Trying cold boot (ouch!)\n", dpt->unit);
1722
1723
1724 if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb,
1725 EATA_COLD_BOOT, 0, 0,
1726 0, 0)) != 0) {
1727 panic("dpt%d: Faild to cold boot the HBA\n",
1728 dpt->unit);
1729 }
1730#ifdef DPT_MEASURE_PERFORMANCE
1731 dpt->performance.cold_boots++;
1732#endif /* DPT_MEASURE_PERFORMANCE */
1733 }
1734
1735#ifdef DPT_MEASURE_PERFORMANCE
1736 dpt->performance.warm_starts++;
1737#endif /* DPT_MEASURE_PERFORMANCE */
1738
1739 printf("dpt%d: Aborting pending requests. O/S should re-submit\n",
1740 dpt->unit);
1741
1742 while ((dccbp = TAILQ_FIRST(&dpt->completed_ccbs)) != NULL) {
1743 struct scsi_xfer *xs = dccbp->xs;
1744
1745 /* Not all transactions have xs structs */
1746 if (xs != NULL) {
1747 /* Tell the kernel proper this did not complete well */
1748 xs->error |= XS_SELTIMEOUT;
1749 xs->flags |= SCSI_ITSDONE;
1750 scsi_done(xs);
1751 }
1752
1753 dpt_Qremove_submitted(dpt, dccbp);
1754
1755 /* Remember, Callbacks are NOT in the standard queue */
1756 if (dccbp->std_callback != NULL) {
1757 (dccbp->std_callback)(dpt, dccbp->eata_ccb.cp_channel,
1758 dccbp);
1759 } else {
1760 ospl = splcam();
1761 dpt_Qpush_free(dpt, dccbp);
1762 splx(ospl);
1763 }
1764 }
1765
1766 printf("dpt%d: reset done aborting all pending commands\n", dpt->unit);
1767 dpt->queue_status &= ~DPT_SUBMITTED_QUEUE_ACTIVE;
1768}
1769
1770#endif /* DPT_RESET_HBA */
1771
1772/*
1773 * Build a Command Block for target mode READ/WRITE BUFFER,
1774 * with the ``sync'' bit ON.
1775 *
1776 * Although the length and offset are 24 bit fields in the command, they cannot
1777 * exceed 8192 bytes, so we take them as short integers andcheck their range.
1778 * If they are sensless, we round them to zero offset, maximum length and
1779 * complain.
1780 */
1781
1782static void
1783dpt_target_ccb(dpt_softc_t * dpt, int bus, u_int8_t target, u_int8_t lun,
1784 dpt_ccb_t * ccb, int mode, u_int8_t command,
1785 u_int16_t length, u_int16_t offset)
1786{
1787 eata_ccb_t *cp;
1788 int ospl;
1789
1790 if ((length + offset) > DPT_MAX_TARGET_MODE_BUFFER_SIZE) {
1791 printf("dpt%d: Length of %d, and offset of %d are wrong\n",
1792 dpt->unit, length, offset);
1793 length = DPT_MAX_TARGET_MODE_BUFFER_SIZE;
1794 offset = 0;
1795 }
1796 ccb->xs = NULL;
1797 ccb->flags = 0;
1798 ccb->state = DPT_CCB_STATE_NEW;
1799 ccb->std_callback = (ccb_callback) dpt_target_done;
1800 ccb->wrbuff_callback = NULL;
1801
1802 cp = &ccb->eata_ccb;
1803 cp->CP_OpCode = EATA_CMD_DMA_SEND_CP;
1804 cp->SCSI_Reset = 0;
1805 cp->HBA_Init = 0;
1806 cp->Auto_Req_Sen = 1;
1807 cp->cp_id = target;
1808 cp->DataIn = 1;
1809 cp->DataOut = 0;
1810 cp->Interpret = 0;
1811 cp->reqlen = htonl(sizeof(struct scsi_sense_data));
1812 cp->cp_statDMA = htonl(vtophys(&cp->cp_statDMA));
1813 cp->cp_reqDMA = htonl(vtophys(&cp->cp_reqDMA));
1814 cp->cp_viraddr = (u_int32_t) & ccb;
1815
1816 cp->cp_msg[0] = HA_IDENTIFY_MSG | HA_DISCO_RECO;
1817
1818 cp->cp_scsi_cmd = command;
1819 cp->cp_cdb[1] = (u_int8_t) (mode & SCSI_TM_MODE_MASK);
1820 cp->cp_lun = lun; /* Order is important here! */
1821 cp->cp_cdb[2] = 0x00; /* Buffer Id, only 1 :-( */
1822 cp->cp_cdb[3] = (length >> 16) & 0xFF; /* Buffer offset MSB */
1823 cp->cp_cdb[4] = (length >> 8) & 0xFF;
1824 cp->cp_cdb[5] = length & 0xFF;
1825 cp->cp_cdb[6] = (length >> 16) & 0xFF; /* Length MSB */
1826 cp->cp_cdb[7] = (length >> 8) & 0xFF;
1827 cp->cp_cdb[8] = length & 0xFF; /* Length LSB */
1828 cp->cp_cdb[9] = 0; /* No sync, no match bits */
1829
1830 /*
1831 * This could be optimized to live in dpt_register_buffer.
1832 * We keep it here, just in case the kernel decides to reallocate pages
1833 */
1834 if (dpt_scatter_gather(dpt, ccb, DPT_RW_BUFFER_SIZE,
1835 dpt->rw_buffer[bus][target][lun])) {
1836 printf("dpt%d: Failed to setup Scatter/Gather for "
1837 "Target-Mode buffer\n", dpt->unit);
1838 }
1839}
1840
1841/* Setup a target mode READ command */
1842
1843static void
1844dpt_set_target(int redo, dpt_softc_t * dpt,
1845 u_int8_t bus, u_int8_t target, u_int8_t lun, int mode,
1846 u_int16_t length, u_int16_t offset, dpt_ccb_t * ccb)
1847{
1848 int ospl;
1849
1850 if (dpt->target_mode_enabled) {
1851 ospl = splcam();
1852
1853 if (!redo)
1854 dpt_target_ccb(dpt, bus, target, lun, ccb, mode,
1855 SCSI_TM_READ_BUFFER, length, offset);
1856
1857 ccb->transaction_id = ++dpt->commands_processed;
1858
1859#ifdef DPT_MEASURE_PERFORMANCE
1860 dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++;
1861 ccb->command_started = microtime_now;
1862#endif
1863 dpt_Qadd_waiting(dpt, ccb);
1864 dpt_sched_queue(dpt);
1865
1866 splx(ospl);
1867 } else {
1868 printf("dpt%d: Target Mode Request, but Target Mode is OFF\n",
1869 dpt->unit);
1870 }
1871}
1872
1873/*
1874 * Schedule a buffer to be sent to another target.
1875 * The work will be scheduled and the callback provided will be called when
1876 * the work is actually done.
1877 *
1878 * Please NOTE: ``Anyone'' can send a buffer, but only registered clients
1879 * get notified of receipt of buffers.
1880 */
1881
1882int
1883dpt_send_buffer(int unit, u_int8_t channel, u_int8_t target, u_int8_t lun,
1884 u_int8_t mode, u_int16_t length, u_int16_t offset, void *data,
1885 buff_wr_done callback)
1886{
1887 dpt_softc_t *dpt;
1888 dpt_ccb_t *ccb = NULL;
1889 int ospl;
1890
1891 /* This is an external call. Be a bit paranoid */
1892 for (dpt = TAILQ_FIRST(&dpt_softc_list);
1893 dpt != NULL;
1894 dpt = TAILQ_NEXT(dpt, links)) {
1895 if (dpt->unit == unit)
1896 goto valid_unit;
1897 }
1898
1899 return (INVALID_UNIT);
1900
1901valid_unit:
1902
1903 if (dpt->target_mode_enabled) {
1904 if ((channel >= dpt->channels) || (target > dpt->max_id) ||
1905 (lun > dpt->max_lun)) {
1906 return (INVALID_SENDER);
1907 }
1908 if ((dpt->rw_buffer[channel][target][lun] == NULL) ||
1909 (dpt->buffer_receiver[channel][target][lun] == NULL))
1910 return (NOT_REGISTERED);
1911
1912 ospl = splsoftcam();
1913 /* Process the free list */
1914 if ((TAILQ_EMPTY(&dpt->free_ccbs)) && dpt_alloc_freelist(dpt)) {
1915 printf("dpt%d ERROR: Cannot allocate any more free CCB's.\n"
1916 " Please try later\n",
1917 dpt->unit);
1918 splx(ospl);
1919 return (NO_RESOURCES);
1920 }
1921 /* Now grab the newest CCB */
1922 if ((ccb = dpt_Qpop_free(dpt)) == NULL) {
1923 splx(ospl);
1924 panic("dpt%d: Got a NULL CCB from pop_free()\n", dpt->unit);
1925 }
1926 splx(ospl);
1927
1928 bcopy(dpt->rw_buffer[channel][target][lun] + offset, data, length);
1929 dpt_target_ccb(dpt, channel, target, lun, ccb, mode,
1930 SCSI_TM_WRITE_BUFFER,
1931 length, offset);
1932 ccb->std_callback = (ccb_callback) callback; /* Potential trouble */
1933
1934 ospl = splcam();
1935 ccb->transaction_id = ++dpt->commands_processed;
1936
1937#ifdef DPT_MEASURE_PERFORMANCE
1938 dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++;
1939 ccb->command_started = microtime_now;
1940#endif
1941 dpt_Qadd_waiting(dpt, ccb);
1942 dpt_sched_queue(dpt);
1943
1944 splx(ospl);
1945 return (0);
1946 }
1947 return (DRIVER_DOWN);
1948}
1949
1950static void
1951dpt_target_done(dpt_softc_t * dpt, int bus, dpt_ccb_t * ccb)
1952{
1953 int ospl;
1954 eata_ccb_t *cp;
1955
1956 cp = &ccb->eata_ccb;
1957
1958 /*
1959 * Remove the CCB from the waiting queue.
1960 * We do NOT put it back on the free, etc., queues as it is a special
1961 * ccb, owned by the dpt_softc of this unit.
1962 */
1963 ospl = splsoftcam();
1964 dpt_Qremove_completed(dpt, ccb);
1965 splx(ospl);
1966
1967#define br_channel (ccb->eata_ccb.cp_channel)
1968#define br_target (ccb->eata_ccb.cp_id)
1969#define br_lun (ccb->eata_ccb.cp_LUN)
1970#define br_index [br_channel][br_target][br_lun]
1971#define read_buffer_callback (dpt->buffer_receiver br_index )
1972#define read_buffer (dpt->rw_buffer[br_channel][br_target][br_lun])
1973#define cb(offset) (ccb->eata_ccb.cp_cdb[offset])
1974#define br_offset ((cb(3) << 16) | (cb(4) << 8) | cb(5))
1975#define br_length ((cb(6) << 16) | (cb(7) << 8) | cb(8))
1976
1977 /* Different reasons for being here, you know... */
1978 switch (ccb->eata_ccb.cp_scsi_cmd) {
1979 case SCSI_TM_READ_BUFFER:
1980 if (read_buffer_callback != NULL) {
1981 /* This is a buffer generated by a kernel process */
1982 read_buffer_callback(dpt->unit, br_channel,
1983 br_target, br_lun,
1984 read_buffer,
1985 br_offset, br_length);
1986 } else {
1987 /*
1988 * This is a buffer waited for by a user (sleeping)
1989 * command
1990 */
1991 wakeup(ccb);
1992 }
1993
1994 /* We ALWAYS re-issue the same command; args are don't-care */
1995 dpt_set_target(1, 0, 0, 0, 0, 0, 0, 0, 0);
1996 break;
1997
1998 case SCSI_TM_WRITE_BUFFER:
1999 (ccb->wrbuff_callback) (dpt->unit, br_channel, br_target,
2000 br_offset, br_length,
2001 br_lun, ccb->status_packet.hba_stat);
2002 break;
2003 default:
2004 printf("dpt%d: %s is an unsupported command for target mode\n",
2005 dpt->unit, scsi_cmd_name(ccb->eata_ccb.cp_scsi_cmd));
2006 }
2007 ospl = splsoftcam();
2008 dpt->target_ccb[br_channel][br_target][br_lun] = NULL;
2009 dpt_Qpush_free(dpt, ccb);
2010 splx(ospl);
2011}
2012
2013
2014/*
2015 * Use this function to register a client for a buffer read target operation.
2016 * The function you register will be called every time a buffer is received
2017 * by the target mode code.
2018 */
2019dpt_rb_t
2020dpt_register_buffer(int unit, u_int8_t channel, u_int8_t target, u_int8_t lun,
2021 u_int8_t mode, u_int16_t length, u_int16_t offset,
2022 dpt_rec_buff callback, dpt_rb_op_t op)
2023{
2024 dpt_softc_t *dpt;
2025 dpt_ccb_t *ccb = NULL;
2026 int ospl;
2027
2028 for (dpt = TAILQ_FIRST(&dpt_softc_list);
2029 dpt != NULL;
2030 dpt = TAILQ_NEXT(dpt, links)) {
2031 if (dpt->unit == unit)
2032 goto valid_unit;
2033 }
2034
2035 return (INVALID_UNIT);
2036
2037valid_unit:
2038
2039 if (dpt->state & DPT_HA_SHUTDOWN_ACTIVE)
2040 return (DRIVER_DOWN);
2041
2042 if ((channel > (dpt->channels - 1)) || (target > (dpt->max_id - 1)) ||
2043 (lun > (dpt->max_lun - 1)))
2044 return (INVALID_SENDER);
2045
2046 if (dpt->buffer_receiver[channel][target][lun] == NULL) {
2047 if (op == REGISTER_BUFFER) {
2048 /* Assign the requested callback */
2049 dpt->buffer_receiver[channel][target][lun] = callback;
2050 /* Get a CCB */
2051 ospl = splsoftcam();
2052
2053 /* Process the free list */
2054 if ((TAILQ_EMPTY(&dpt->free_ccbs)) && dpt_alloc_freelist(dpt)) {
2055 printf("dpt%d ERROR: Cannot allocate any more free CCB's.\n"
2056 " Please try later\n",
2057 dpt->unit);
2058 splx(ospl);
2059 return (NO_RESOURCES);
2060 }
2061 /* Now grab the newest CCB */
2062 if ((ccb = dpt_Qpop_free(dpt)) == NULL) {
2063 splx(ospl);
2064 panic("dpt%d: Got a NULL CCB from pop_free()\n",
2065 dpt->unit);
2066 }
2067 splx(ospl);
2068
2069 /* Clean up the leftover of the previous tenant */
2070 ccb->status = DPT_CCB_STATE_NEW;
2071 dpt->target_ccb[channel][target][lun] = ccb;
2072
2073 dpt->rw_buffer[channel][target][lun] =
2074 malloc(DPT_RW_BUFFER_SIZE, M_DEVBUF, M_NOWAIT);
2075 if (dpt->rw_buffer[channel][target][lun] == NULL) {
2076 printf("dpt%d: Failed to allocate "
2077 "Target-Mode buffer\n", dpt->unit);
2078 ospl = splsoftcam();
2079 dpt_Qpush_free(dpt, ccb);
2080 splx(ospl);
2081 return (NO_RESOURCES);
2082 }
2083 dpt_set_target(0, dpt, channel, target, lun, mode,
2084 length, offset, ccb);
2085 return (SUCCESSFULLY_REGISTERED);
2086 } else
2087 return (NOT_REGISTERED);
2088 } else {
2089 if (op == REGISTER_BUFFER) {
2090 if (dpt->buffer_receiver[channel][target][lun] == callback)
2091 return (ALREADY_REGISTERED);
2092 else
2093 return (REGISTERED_TO_ANOTHER);
2094 } else {
2095 if (dpt->buffer_receiver[channel][target][lun] == callback) {
2096 dpt->buffer_receiver[channel][target][lun] = NULL;
2097 ospl = splsoftcam();
2098 dpt_Qpush_free(dpt, ccb);
2099 splx(ospl);
2100 free(dpt->rw_buffer[channel][target][lun], M_DEVBUF);
2101 return (SUCCESSFULLY_REGISTERED);
2102 } else
2103 return (INVALID_CALLBACK);
2104 }
2105
2106 }
2107}
2108
2109/* Return the state of the blinking DPT LED's */
2110u_int8_t
2111dpt_blinking_led(dpt_softc_t * dpt)
2112{
2113 int ndx;
2114 int ospl;
2115 u_int32_t state;
2116 u_int32_t previous;
2117 u_int8_t result;
2118
2119 ospl = splcam();
2120
2121 result = 0;
2122
2123 for (ndx = 0, state = 0, previous = 0;
2124 (ndx < 10) && (state != previous);
2125 ndx++) {
2126 previous = state;
2127 state = dpt_inl(dpt, 1);
2128 }
2129
2130 if ((state == previous) && (state == DPT_BLINK_INDICATOR))
2131 result = dpt_inb(dpt, 5);
2132
2133 splx(ospl);
2134 return (result);
2135}
2136
2137/*
2138 * Execute a command which did not come from the kernel's SCSI layer.
2139 * The only way to map user commands to bus and target is to comply with the
2140 * standard DPT wire-down scheme:
2141 */
2142int
2143dpt_user_cmd(dpt_softc_t * dpt, eata_pt_t * user_cmd,
2144 caddr_t cmdarg, int minor_no)
2145{
2146 dpt_ccb_t *ccb;
2147 void *data;
2148 int channel, target, lun;
2149 int huh;
2150 int result;
2151 int ospl;
2152 int submitted;
2153
2154 data = NULL;
2155 channel = minor2hba(minor_no);
2156 target = minor2target(minor_no);
2157 lun = minor2lun(minor_no);
2158
2159 if ((channel > (dpt->channels - 1))
2160 || (target > dpt->max_id)
2161 || (lun > dpt->max_lun))
2162 return (ENXIO);
2163
2164 if (target == dpt->sc_scsi_link[channel].adapter_targ) {
2165 /* This one is for the controller itself */
2166 if ((user_cmd->eataID[0] != 'E')
2167 || (user_cmd->eataID[1] != 'A')
2168 || (user_cmd->eataID[2] != 'T')
2169 || (user_cmd->eataID[3] != 'A')) {
2170 return (ENXIO);
2171 }
2172 }
2173 /* Get a DPT CCB, so we can prepare a command */
2174 ospl = splsoftcam();
2175
2176 /* Process the free list */
2177 if ((TAILQ_EMPTY(&dpt->free_ccbs)) && dpt_alloc_freelist(dpt)) {
2178 printf("dpt%d ERROR: Cannot allocate any more free CCB's.\n"
2179 " Please try later\n",
2180 dpt->unit);
2181 splx(ospl);
2182 return (EFAULT);
2183 }
2184 /* Now grab the newest CCB */
2185 if ((ccb = dpt_Qpop_free(dpt)) == NULL) {
2186 splx(ospl);
2187 panic("dpt%d: Got a NULL CCB from pop_free()\n", dpt->unit);
2188 } else {
2189 splx(ospl);
2190 /* Clean up the leftover of the previous tenant */
2191 ccb->status = DPT_CCB_STATE_NEW;
2192 }
2193
2194 bcopy((caddr_t) & user_cmd->command_packet, (caddr_t) & ccb->eata_ccb,
2195 sizeof(eata_ccb_t));
2196
2197 /* We do not want to do user specified scatter/gather. Why?? */
2198 if (ccb->eata_ccb.scatter == 1)
2199 return (EINVAL);
2200
2201 ccb->eata_ccb.Auto_Req_Sen = 1;
2202 ccb->eata_ccb.reqlen = htonl(sizeof(struct scsi_sense_data));
2203 ccb->eata_ccb.cp_datalen = htonl(sizeof(ccb->eata_ccb.cp_datalen));
2204 ccb->eata_ccb.cp_dataDMA = htonl(vtophys(ccb->eata_ccb.cp_dataDMA));
2205 ccb->eata_ccb.cp_statDMA = htonl(vtophys(&ccb->eata_ccb.cp_statDMA));
2206 ccb->eata_ccb.cp_reqDMA = htonl(vtophys(&ccb->eata_ccb.cp_reqDMA));
2207 ccb->eata_ccb.cp_viraddr = (u_int32_t) & ccb;
2208
2209 if (ccb->eata_ccb.DataIn || ccb->eata_ccb.DataOut) {
2210 /* Data I/O is involved in this command. Alocate buffer */
2211 if (ccb->eata_ccb.cp_datalen > PAGE_SIZE) {
2212 data = contigmalloc(ccb->eata_ccb.cp_datalen,
2213 M_TEMP, M_WAITOK, 0, ~0,
2214 ccb->eata_ccb.cp_datalen,
2215 0x10000);
2216 } else {
2217 data = malloc(ccb->eata_ccb.cp_datalen, M_TEMP,
2218 M_WAITOK);
2219 }
2220
2221 if (data == NULL) {
2222 printf("dpt%d: Cannot allocate %d bytes "
2223 "for EATA command\n", dpt->unit,
2224 ccb->eata_ccb.cp_datalen);
2225 return (EFAULT);
2226 }
2227#define usr_cmd_DMA (caddr_t)user_cmd->command_packet.cp_dataDMA
2228 if (ccb->eata_ccb.DataIn == 1) {
2229 if (copyin(usr_cmd_DMA,
2230 data, ccb->eata_ccb.cp_datalen) == -1)
2231 return (EFAULT);
2232 }
2233 } else {
2234 /* No data I/O involved here. Make sure the DPT knows that */
2235 ccb->eata_ccb.cp_datalen = 0;
2236 data = NULL;
2237 }
2238
2239 if (ccb->eata_ccb.FWNEST == 1)
2240 ccb->eata_ccb.FWNEST = 0;
2241
2242 if (ccb->eata_ccb.cp_datalen != 0) {
2243 if (dpt_scatter_gather(dpt, ccb, ccb->eata_ccb.cp_datalen,
2244 data) != 0) {
2245 if (data != NULL)
2246 free(data, M_TEMP);
2247 return (EFAULT);
2248 }
2249 }
2250 /**
2251 * We are required to quiet a SCSI bus.
2252 * since we do not queue comands on a bus basis,
2253 * we wait for ALL commands on a controller to complete.
2254 * In the mean time, sched_queue() will not schedule new commands.
2255 */
2256 if ((ccb->eata_ccb.cp_cdb[0] == MULTIFUNCTION_CMD)
2257 && (ccb->eata_ccb.cp_cdb[2] == BUS_QUIET)) {
2258 /* We wait for ALL traffic for this HBa to subside */
2259 ospl = splsoftcam();
2260 dpt->state |= DPT_HA_QUIET;
2261 splx(ospl);
2262
2263 while ((submitted = dpt->submitted_ccbs_count) != 0) {
2264 huh = tsleep((void *) dpt, PCATCH | PRIBIO, "dptqt",
2265 100 * hz);
2266 switch (huh) {
2267 case 0:
2268 /* Wakeup call received */
2269 break;
2270 case EWOULDBLOCK:
2271 /* Timer Expired */
2272 break;
2273 default:
2274 /* anything else */
2275 break;
2276 }
2277 }
2278 }
2279 /* Resume normal operation */
2280 if ((ccb->eata_ccb.cp_cdb[0] == MULTIFUNCTION_CMD)
2281 && (ccb->eata_ccb.cp_cdb[2] == BUS_UNQUIET)) {
2282 ospl = splsoftcam();
2283 dpt->state &= ~DPT_HA_QUIET;
2284 splx(ospl);
2285 }
2286 /**
2287 * Schedule the command and submit it.
2288 * We bypass dpt_sched_queue, as it will block on DPT_HA_QUIET
2289 */
2290 ccb->xs = NULL;
2291 ccb->flags = 0;
2292 ccb->eata_ccb.Auto_Req_Sen = 1; /* We always want this feature */
2293
2294 ccb->transaction_id = ++dpt->commands_processed;
2295 ccb->std_callback = (ccb_callback) dpt_user_cmd_done;
2296 ccb->result = (u_int32_t) & cmdarg;
2297 ccb->data = data;
2298
2299#ifdef DPT_MEASURE_PERFORMANCE
2300 ++dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd];
2301 ccb->command_started = microtime_now;
2302#endif
2303 ospl = splcam();
2304 dpt_Qadd_waiting(dpt, ccb);
2305 splx(ospl);
2306
2307 dpt_sched_queue(dpt);
2308
2309 /* Wait for the command to complete */
2310 (void) tsleep((void *) ccb, PCATCH | PRIBIO, "dptucw", 100 * hz);
2311
2312 /* Free allocated memory */
2313 if (data != NULL)
2314 free(data, M_TEMP);
2315
2316 return (0);
2317}
2318
2319static void
2320dpt_user_cmd_done(dpt_softc_t * dpt, int bus, dpt_ccb_t * ccb)
2321{
2322 int ospl = splsoftcam();
2323 u_int32_t result;
2324 caddr_t cmd_arg;
2325
2326 /**
2327 * If Auto Request Sense is on, copyout the sense struct
2328 */
2329#define usr_pckt_DMA (caddr_t)(intptr_t)ntohl(ccb->eata_ccb.cp_reqDMA)
2330#define usr_pckt_len ntohl(ccb->eata_ccb.cp_datalen)
2331 if (ccb->eata_ccb.Auto_Req_Sen == 1) {
2332 if (copyout((caddr_t) & ccb->sense_data, usr_pckt_DMA,
2333 sizeof(struct scsi_sense_data))) {
2334 ccb->result = EFAULT;
2335 dpt_Qpush_free(dpt, ccb);
2336 splx(ospl);
2337 wakeup(ccb);
2338 return;
2339 }
2340 }
2341 /* If DataIn is on, copyout the data */
2342 if ((ccb->eata_ccb.DataIn == 1)
2343 && (ccb->status_packet.hba_stat == HA_NO_ERROR)) {
2344 if (copyout(ccb->data, usr_pckt_DMA, usr_pckt_len)) {
2345 dpt_Qpush_free(dpt, ccb);
2346 ccb->result = EFAULT;
2347
2348 splx(ospl);
2349 wakeup(ccb);
2350 return;
2351 }
2352 }
2353 /* Copyout the status */
2354 result = ccb->status_packet.hba_stat;
2355 cmd_arg = (caddr_t) ccb->result;
2356
2357 if (copyout((caddr_t) & result, cmd_arg, sizeof(result))) {
2358 dpt_Qpush_free(dpt, ccb);
2359 ccb->result = EFAULT;
2360 splx(ospl);
2361 wakeup(ccb);
2362 return;
2363 }
2364 /* Put the CCB back in the freelist */
2365 ccb->state |= DPT_CCB_STATE_COMPLETED;
2366 dpt_Qpush_free(dpt, ccb);
2367
2368 /* Free allocated memory */
2369 splx(ospl);
2370 return;
2371}
2372
2373#ifdef DPT_HANDLE_TIMEOUTS
2374/**
2375 * This function walks down the SUBMITTED queue.
2376 * Every request that is too old gets aborted and marked.
2377 * Since the DPT will complete (interrupt) immediately (what does that mean?),
2378 * We just walk the list, aborting old commands and marking them as such.
2379 * The dpt_complete function will get rid of the that were interrupted in the
2380 * normal manner.
2381 *
2382 * This function needs to run at splcam(), as it interacts with the submitted
2383 * queue, as well as the completed and free queues. Just like dpt_intr() does.
2384 * To run it at any ISPL other than that of dpt_intr(), will mean that dpt_intr
2385 * willbe able to pre-empt it, grab a transaction in progress (towards
2386 * destruction) and operate on it. The state of this transaction will be not
2387 * very clear.
2388 * The only other option, is to lock it only as long as necessary but have
2389 * dpt_intr() spin-wait on it. In a UP environment this makes no sense and in
2390 * a SMP environment, the advantage is dubvious for a function that runs once
2391 * every ten seconds for few microseconds and, on systems with healthy
2392 * hardware, does not do anything anyway.
2393 */
2394
2395static void
2396dpt_handle_timeouts(dpt_softc_t * dpt)
2397{
2398 dpt_ccb_t *ccb;
2399 int ospl;
2400
2401 ospl = splcam();
2402
2403 if (dpt->state & DPT_HA_TIMEOUTS_ACTIVE) {
2404 printf("dpt%d WARNING: Timeout Handling Collision\n",
2405 dpt->unit);
2406 splx(ospl);
2407 return;
2408 }
2409 dpt->state |= DPT_HA_TIMEOUTS_ACTIVE;
2410
2411 /* Loop through the entire submitted queue, looking for lost souls */
2412 for (ccb = TAILQ_FIRST(&dpt->submitted_ccbs);
2413 ccb != NULL;
2414 ccb = TAILQ_NEXT(ccb, links)) {
2415 struct scsi_xfer *xs;
2416 u_int32_t age, max_age;
2417
2418 xs = ccb->xs;
2419 age = dpt_time_delta(ccb->command_started, microtime_now);
2420
2421#define TenSec 10000000
2422
2423 if (xs == NULL) { /* Local, non-kernel call */
2424 max_age = TenSec;
2425 } else {
2426 max_age = (((xs->timeout * (dpt->submitted_ccbs_count
2427 + DPT_TIMEOUT_FACTOR))
2428 > TenSec)
2429 ? (xs->timeout * (dpt->submitted_ccbs_count
2430 + DPT_TIMEOUT_FACTOR))
2431 : TenSec);
2432 }
2433
2434 /*
2435 * If a transaction is marked lost and is TWICE as old as we
2436 * care, then, and only then do we destroy it!
2437 */
2438 if (ccb->state & DPT_CCB_STATE_MARKED_LOST) {
2439 /* Remember who is next */
2440 if (age > (max_age * 2)) {
2441 dpt_Qremove_submitted(dpt, ccb);
2442 ccb->state &= ~DPT_CCB_STATE_MARKED_LOST;
2443 ccb->state |= DPT_CCB_STATE_ABORTED;
2444#define cmd_name scsi_cmd_name(ccb->eata_ccb.cp_scsi_cmd)
2445 if (ccb->retries++ > DPT_RETRIES) {
2446 printf("dpt%d ERROR: Destroying stale "
2447 "%d (%s)\n"
2448 " on "
2449 "c%db%dt%du%d (%d/%d)\n",
2450 dpt->unit, ccb->transaction_id,
2451 cmd_name,
2452 dpt->unit,
2453 ccb->eata_ccb.cp_channel,
2454 ccb->eata_ccb.cp_id,
2455 ccb->eata_ccb.cp_LUN, age,
2456 ccb->retries);
2457#define send_ccb &ccb->eata_ccb
2458#define ESA EATA_SPECIFIC_ABORT
2459 (void) dpt_send_immediate(dpt,
2460 send_ccb,
2461 ESA,
2462 0, 0);
2463 dpt_Qpush_free(dpt, ccb);
2464
2465 /* The SCSI layer should re-try */
2466 xs->error |= XS_TIMEOUT;
2467 xs->flags |= SCSI_ITSDONE;
2468 scsi_done(xs);
2469 } else {
2470 printf("dpt%d ERROR: Stale %d (%s) on "
2471 "c%db%dt%du%d (%d)\n"
2472 " gets another "
2473 "chance(%d/%d)\n",
2474 dpt->unit, ccb->transaction_id,
2475 cmd_name,
2476 dpt->unit,
2477 ccb->eata_ccb.cp_channel,
2478 ccb->eata_ccb.cp_id,
2479 ccb->eata_ccb.cp_LUN,
2480 age, ccb->retries, DPT_RETRIES);
2481
2482 dpt_Qpush_waiting(dpt, ccb);
2483 dpt_sched_queue(dpt);
2484 }
2485 }
2486 } else {
2487 /*
2488 * This is a transaction that is not to be destroyed
2489 * (yet) But it is too old for our liking. We wait as
2490 * long as the upper layer thinks. Not really, we
2491 * multiply that by the number of commands in the
2492 * submitted queue + 1.
2493 */
2494 if (!(ccb->state & DPT_CCB_STATE_MARKED_LOST) &&
2495 (age != ~0) && (age > max_age)) {
2496 printf("dpt%d ERROR: Marking %d (%s) on "
2497 "c%db%dt%du%d \n"
2498 " as late after %dusec\n",
2499 dpt->unit, ccb->transaction_id,
2500 cmd_name,
2501 dpt->unit, ccb->eata_ccb.cp_channel,
2502 ccb->eata_ccb.cp_id,
2503 ccb->eata_ccb.cp_LUN, age);
2504 ccb->state |= DPT_CCB_STATE_MARKED_LOST;
2505 }
2506 }
2507 }
2508
2509 dpt->state &= ~DPT_HA_TIMEOUTS_ACTIVE;
2510 splx(ospl);
2511}
2512
2513static void
2514dpt_timeout(void *arg)
2515{
2516 dpt_softc_t *dpt = (dpt_softc_t *) arg;
2517
2518 if (!(dpt->state & DPT_HA_TIMEOUTS_ACTIVE))
2519 dpt_handle_timeouts(dpt);
2520
2521 timeout(dpt_timeout, (caddr_t) dpt, hz * 10);
2522}
2523
2524#endif /* DPT_HANDLE_TIMEOUTS */
2525
2526#endif
1647{
1648 dpt_softc_t *dpt;
1649
1650 dpt = (dpt_softc_t *)arg;
1651
1652 printf("dpt%d: Shutting down (mode %x) HBA. Please wait...\n",
1653 dpt->unit, howto);
1654
1655 /*
1656 * What we do for a shutdown, is give the DPT early power loss warning
1657 */
1658 dpt_send_immediate(dpt, NULL, 0, EATA_POWER_OFF_WARN, 0, 0, 0);
1659 DELAY(1000 * 1000 * 5);
1660 printf("dpt%d: Controller was warned of shutdown and is now "
1661 "disabled\n", dpt->unit);
1662}
1663
1664/*============================================================================*/
1665
1666#if 0
1667#ifdef DPT_RESET_HBA
1668
1669/*
1670** Function name : dpt_reset_hba
1671**
1672** Description : Reset the HBA and properly discard all pending work
1673** Input : Softc
1674** Output : Nothing
1675*/
1676static void
1677dpt_reset_hba(dpt_softc_t *dpt)
1678{
1679 eata_ccb_t *ccb;
1680 int ospl;
1681 dpt_ccb_t dccb, *dccbp;
1682 int result;
1683 struct scsi_xfer *xs;
1684
1685 /* Prepare a control block. The SCSI command part is immaterial */
1686 dccb.xs = NULL;
1687 dccb.flags = 0;
1688 dccb.state = DPT_CCB_STATE_NEW;
1689 dccb.std_callback = NULL;
1690 dccb.wrbuff_callback = NULL;
1691
1692 ccb = &dccb.eata_ccb;
1693 ccb->CP_OpCode = EATA_CMD_RESET;
1694 ccb->SCSI_Reset = 0;
1695 ccb->HBA_Init = 1;
1696 ccb->Auto_Req_Sen = 1;
1697 ccb->cp_id = 0; /* Should be ignored */
1698 ccb->DataIn = 1;
1699 ccb->DataOut = 0;
1700 ccb->Interpret = 1;
1701 ccb->reqlen = htonl(sizeof(struct scsi_sense_data));
1702 ccb->cp_statDMA = htonl(vtophys(&ccb->cp_statDMA));
1703 ccb->cp_reqDMA = htonl(vtophys(&ccb->cp_reqDMA));
1704 ccb->cp_viraddr = (u_int32_t) & ccb;
1705
1706 ccb->cp_msg[0] = HA_IDENTIFY_MSG | HA_DISCO_RECO;
1707 ccb->cp_scsi_cmd = 0; /* Should be ignored */
1708
1709 /* Lock up the submitted queue. We are very persistant here */
1710 ospl = splcam();
1711 while (dpt->queue_status & DPT_SUBMITTED_QUEUE_ACTIVE) {
1712 DELAY(100);
1713 }
1714
1715 dpt->queue_status |= DPT_SUBMITTED_QUEUE_ACTIVE;
1716 splx(ospl);
1717
1718 /* Send the RESET message */
1719 if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb,
1720 EATA_CMD_RESET, 0, 0, 0, 0)) != 0) {
1721 printf("dpt%d: Failed to send the RESET message.\n"
1722 " Trying cold boot (ouch!)\n", dpt->unit);
1723
1724
1725 if ((result = dpt_send_eata_command(dpt, &dccb.eata_ccb,
1726 EATA_COLD_BOOT, 0, 0,
1727 0, 0)) != 0) {
1728 panic("dpt%d: Faild to cold boot the HBA\n",
1729 dpt->unit);
1730 }
1731#ifdef DPT_MEASURE_PERFORMANCE
1732 dpt->performance.cold_boots++;
1733#endif /* DPT_MEASURE_PERFORMANCE */
1734 }
1735
1736#ifdef DPT_MEASURE_PERFORMANCE
1737 dpt->performance.warm_starts++;
1738#endif /* DPT_MEASURE_PERFORMANCE */
1739
1740 printf("dpt%d: Aborting pending requests. O/S should re-submit\n",
1741 dpt->unit);
1742
1743 while ((dccbp = TAILQ_FIRST(&dpt->completed_ccbs)) != NULL) {
1744 struct scsi_xfer *xs = dccbp->xs;
1745
1746 /* Not all transactions have xs structs */
1747 if (xs != NULL) {
1748 /* Tell the kernel proper this did not complete well */
1749 xs->error |= XS_SELTIMEOUT;
1750 xs->flags |= SCSI_ITSDONE;
1751 scsi_done(xs);
1752 }
1753
1754 dpt_Qremove_submitted(dpt, dccbp);
1755
1756 /* Remember, Callbacks are NOT in the standard queue */
1757 if (dccbp->std_callback != NULL) {
1758 (dccbp->std_callback)(dpt, dccbp->eata_ccb.cp_channel,
1759 dccbp);
1760 } else {
1761 ospl = splcam();
1762 dpt_Qpush_free(dpt, dccbp);
1763 splx(ospl);
1764 }
1765 }
1766
1767 printf("dpt%d: reset done aborting all pending commands\n", dpt->unit);
1768 dpt->queue_status &= ~DPT_SUBMITTED_QUEUE_ACTIVE;
1769}
1770
1771#endif /* DPT_RESET_HBA */
1772
1773/*
1774 * Build a Command Block for target mode READ/WRITE BUFFER,
1775 * with the ``sync'' bit ON.
1776 *
1777 * Although the length and offset are 24 bit fields in the command, they cannot
1778 * exceed 8192 bytes, so we take them as short integers andcheck their range.
1779 * If they are sensless, we round them to zero offset, maximum length and
1780 * complain.
1781 */
1782
1783static void
1784dpt_target_ccb(dpt_softc_t * dpt, int bus, u_int8_t target, u_int8_t lun,
1785 dpt_ccb_t * ccb, int mode, u_int8_t command,
1786 u_int16_t length, u_int16_t offset)
1787{
1788 eata_ccb_t *cp;
1789 int ospl;
1790
1791 if ((length + offset) > DPT_MAX_TARGET_MODE_BUFFER_SIZE) {
1792 printf("dpt%d: Length of %d, and offset of %d are wrong\n",
1793 dpt->unit, length, offset);
1794 length = DPT_MAX_TARGET_MODE_BUFFER_SIZE;
1795 offset = 0;
1796 }
1797 ccb->xs = NULL;
1798 ccb->flags = 0;
1799 ccb->state = DPT_CCB_STATE_NEW;
1800 ccb->std_callback = (ccb_callback) dpt_target_done;
1801 ccb->wrbuff_callback = NULL;
1802
1803 cp = &ccb->eata_ccb;
1804 cp->CP_OpCode = EATA_CMD_DMA_SEND_CP;
1805 cp->SCSI_Reset = 0;
1806 cp->HBA_Init = 0;
1807 cp->Auto_Req_Sen = 1;
1808 cp->cp_id = target;
1809 cp->DataIn = 1;
1810 cp->DataOut = 0;
1811 cp->Interpret = 0;
1812 cp->reqlen = htonl(sizeof(struct scsi_sense_data));
1813 cp->cp_statDMA = htonl(vtophys(&cp->cp_statDMA));
1814 cp->cp_reqDMA = htonl(vtophys(&cp->cp_reqDMA));
1815 cp->cp_viraddr = (u_int32_t) & ccb;
1816
1817 cp->cp_msg[0] = HA_IDENTIFY_MSG | HA_DISCO_RECO;
1818
1819 cp->cp_scsi_cmd = command;
1820 cp->cp_cdb[1] = (u_int8_t) (mode & SCSI_TM_MODE_MASK);
1821 cp->cp_lun = lun; /* Order is important here! */
1822 cp->cp_cdb[2] = 0x00; /* Buffer Id, only 1 :-( */
1823 cp->cp_cdb[3] = (length >> 16) & 0xFF; /* Buffer offset MSB */
1824 cp->cp_cdb[4] = (length >> 8) & 0xFF;
1825 cp->cp_cdb[5] = length & 0xFF;
1826 cp->cp_cdb[6] = (length >> 16) & 0xFF; /* Length MSB */
1827 cp->cp_cdb[7] = (length >> 8) & 0xFF;
1828 cp->cp_cdb[8] = length & 0xFF; /* Length LSB */
1829 cp->cp_cdb[9] = 0; /* No sync, no match bits */
1830
1831 /*
1832 * This could be optimized to live in dpt_register_buffer.
1833 * We keep it here, just in case the kernel decides to reallocate pages
1834 */
1835 if (dpt_scatter_gather(dpt, ccb, DPT_RW_BUFFER_SIZE,
1836 dpt->rw_buffer[bus][target][lun])) {
1837 printf("dpt%d: Failed to setup Scatter/Gather for "
1838 "Target-Mode buffer\n", dpt->unit);
1839 }
1840}
1841
1842/* Setup a target mode READ command */
1843
1844static void
1845dpt_set_target(int redo, dpt_softc_t * dpt,
1846 u_int8_t bus, u_int8_t target, u_int8_t lun, int mode,
1847 u_int16_t length, u_int16_t offset, dpt_ccb_t * ccb)
1848{
1849 int ospl;
1850
1851 if (dpt->target_mode_enabled) {
1852 ospl = splcam();
1853
1854 if (!redo)
1855 dpt_target_ccb(dpt, bus, target, lun, ccb, mode,
1856 SCSI_TM_READ_BUFFER, length, offset);
1857
1858 ccb->transaction_id = ++dpt->commands_processed;
1859
1860#ifdef DPT_MEASURE_PERFORMANCE
1861 dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++;
1862 ccb->command_started = microtime_now;
1863#endif
1864 dpt_Qadd_waiting(dpt, ccb);
1865 dpt_sched_queue(dpt);
1866
1867 splx(ospl);
1868 } else {
1869 printf("dpt%d: Target Mode Request, but Target Mode is OFF\n",
1870 dpt->unit);
1871 }
1872}
1873
1874/*
1875 * Schedule a buffer to be sent to another target.
1876 * The work will be scheduled and the callback provided will be called when
1877 * the work is actually done.
1878 *
1879 * Please NOTE: ``Anyone'' can send a buffer, but only registered clients
1880 * get notified of receipt of buffers.
1881 */
1882
1883int
1884dpt_send_buffer(int unit, u_int8_t channel, u_int8_t target, u_int8_t lun,
1885 u_int8_t mode, u_int16_t length, u_int16_t offset, void *data,
1886 buff_wr_done callback)
1887{
1888 dpt_softc_t *dpt;
1889 dpt_ccb_t *ccb = NULL;
1890 int ospl;
1891
1892 /* This is an external call. Be a bit paranoid */
1893 for (dpt = TAILQ_FIRST(&dpt_softc_list);
1894 dpt != NULL;
1895 dpt = TAILQ_NEXT(dpt, links)) {
1896 if (dpt->unit == unit)
1897 goto valid_unit;
1898 }
1899
1900 return (INVALID_UNIT);
1901
1902valid_unit:
1903
1904 if (dpt->target_mode_enabled) {
1905 if ((channel >= dpt->channels) || (target > dpt->max_id) ||
1906 (lun > dpt->max_lun)) {
1907 return (INVALID_SENDER);
1908 }
1909 if ((dpt->rw_buffer[channel][target][lun] == NULL) ||
1910 (dpt->buffer_receiver[channel][target][lun] == NULL))
1911 return (NOT_REGISTERED);
1912
1913 ospl = splsoftcam();
1914 /* Process the free list */
1915 if ((TAILQ_EMPTY(&dpt->free_ccbs)) && dpt_alloc_freelist(dpt)) {
1916 printf("dpt%d ERROR: Cannot allocate any more free CCB's.\n"
1917 " Please try later\n",
1918 dpt->unit);
1919 splx(ospl);
1920 return (NO_RESOURCES);
1921 }
1922 /* Now grab the newest CCB */
1923 if ((ccb = dpt_Qpop_free(dpt)) == NULL) {
1924 splx(ospl);
1925 panic("dpt%d: Got a NULL CCB from pop_free()\n", dpt->unit);
1926 }
1927 splx(ospl);
1928
1929 bcopy(dpt->rw_buffer[channel][target][lun] + offset, data, length);
1930 dpt_target_ccb(dpt, channel, target, lun, ccb, mode,
1931 SCSI_TM_WRITE_BUFFER,
1932 length, offset);
1933 ccb->std_callback = (ccb_callback) callback; /* Potential trouble */
1934
1935 ospl = splcam();
1936 ccb->transaction_id = ++dpt->commands_processed;
1937
1938#ifdef DPT_MEASURE_PERFORMANCE
1939 dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd]++;
1940 ccb->command_started = microtime_now;
1941#endif
1942 dpt_Qadd_waiting(dpt, ccb);
1943 dpt_sched_queue(dpt);
1944
1945 splx(ospl);
1946 return (0);
1947 }
1948 return (DRIVER_DOWN);
1949}
1950
1951static void
1952dpt_target_done(dpt_softc_t * dpt, int bus, dpt_ccb_t * ccb)
1953{
1954 int ospl;
1955 eata_ccb_t *cp;
1956
1957 cp = &ccb->eata_ccb;
1958
1959 /*
1960 * Remove the CCB from the waiting queue.
1961 * We do NOT put it back on the free, etc., queues as it is a special
1962 * ccb, owned by the dpt_softc of this unit.
1963 */
1964 ospl = splsoftcam();
1965 dpt_Qremove_completed(dpt, ccb);
1966 splx(ospl);
1967
1968#define br_channel (ccb->eata_ccb.cp_channel)
1969#define br_target (ccb->eata_ccb.cp_id)
1970#define br_lun (ccb->eata_ccb.cp_LUN)
1971#define br_index [br_channel][br_target][br_lun]
1972#define read_buffer_callback (dpt->buffer_receiver br_index )
1973#define read_buffer (dpt->rw_buffer[br_channel][br_target][br_lun])
1974#define cb(offset) (ccb->eata_ccb.cp_cdb[offset])
1975#define br_offset ((cb(3) << 16) | (cb(4) << 8) | cb(5))
1976#define br_length ((cb(6) << 16) | (cb(7) << 8) | cb(8))
1977
1978 /* Different reasons for being here, you know... */
1979 switch (ccb->eata_ccb.cp_scsi_cmd) {
1980 case SCSI_TM_READ_BUFFER:
1981 if (read_buffer_callback != NULL) {
1982 /* This is a buffer generated by a kernel process */
1983 read_buffer_callback(dpt->unit, br_channel,
1984 br_target, br_lun,
1985 read_buffer,
1986 br_offset, br_length);
1987 } else {
1988 /*
1989 * This is a buffer waited for by a user (sleeping)
1990 * command
1991 */
1992 wakeup(ccb);
1993 }
1994
1995 /* We ALWAYS re-issue the same command; args are don't-care */
1996 dpt_set_target(1, 0, 0, 0, 0, 0, 0, 0, 0);
1997 break;
1998
1999 case SCSI_TM_WRITE_BUFFER:
2000 (ccb->wrbuff_callback) (dpt->unit, br_channel, br_target,
2001 br_offset, br_length,
2002 br_lun, ccb->status_packet.hba_stat);
2003 break;
2004 default:
2005 printf("dpt%d: %s is an unsupported command for target mode\n",
2006 dpt->unit, scsi_cmd_name(ccb->eata_ccb.cp_scsi_cmd));
2007 }
2008 ospl = splsoftcam();
2009 dpt->target_ccb[br_channel][br_target][br_lun] = NULL;
2010 dpt_Qpush_free(dpt, ccb);
2011 splx(ospl);
2012}
2013
2014
2015/*
2016 * Use this function to register a client for a buffer read target operation.
2017 * The function you register will be called every time a buffer is received
2018 * by the target mode code.
2019 */
2020dpt_rb_t
2021dpt_register_buffer(int unit, u_int8_t channel, u_int8_t target, u_int8_t lun,
2022 u_int8_t mode, u_int16_t length, u_int16_t offset,
2023 dpt_rec_buff callback, dpt_rb_op_t op)
2024{
2025 dpt_softc_t *dpt;
2026 dpt_ccb_t *ccb = NULL;
2027 int ospl;
2028
2029 for (dpt = TAILQ_FIRST(&dpt_softc_list);
2030 dpt != NULL;
2031 dpt = TAILQ_NEXT(dpt, links)) {
2032 if (dpt->unit == unit)
2033 goto valid_unit;
2034 }
2035
2036 return (INVALID_UNIT);
2037
2038valid_unit:
2039
2040 if (dpt->state & DPT_HA_SHUTDOWN_ACTIVE)
2041 return (DRIVER_DOWN);
2042
2043 if ((channel > (dpt->channels - 1)) || (target > (dpt->max_id - 1)) ||
2044 (lun > (dpt->max_lun - 1)))
2045 return (INVALID_SENDER);
2046
2047 if (dpt->buffer_receiver[channel][target][lun] == NULL) {
2048 if (op == REGISTER_BUFFER) {
2049 /* Assign the requested callback */
2050 dpt->buffer_receiver[channel][target][lun] = callback;
2051 /* Get a CCB */
2052 ospl = splsoftcam();
2053
2054 /* Process the free list */
2055 if ((TAILQ_EMPTY(&dpt->free_ccbs)) && dpt_alloc_freelist(dpt)) {
2056 printf("dpt%d ERROR: Cannot allocate any more free CCB's.\n"
2057 " Please try later\n",
2058 dpt->unit);
2059 splx(ospl);
2060 return (NO_RESOURCES);
2061 }
2062 /* Now grab the newest CCB */
2063 if ((ccb = dpt_Qpop_free(dpt)) == NULL) {
2064 splx(ospl);
2065 panic("dpt%d: Got a NULL CCB from pop_free()\n",
2066 dpt->unit);
2067 }
2068 splx(ospl);
2069
2070 /* Clean up the leftover of the previous tenant */
2071 ccb->status = DPT_CCB_STATE_NEW;
2072 dpt->target_ccb[channel][target][lun] = ccb;
2073
2074 dpt->rw_buffer[channel][target][lun] =
2075 malloc(DPT_RW_BUFFER_SIZE, M_DEVBUF, M_NOWAIT);
2076 if (dpt->rw_buffer[channel][target][lun] == NULL) {
2077 printf("dpt%d: Failed to allocate "
2078 "Target-Mode buffer\n", dpt->unit);
2079 ospl = splsoftcam();
2080 dpt_Qpush_free(dpt, ccb);
2081 splx(ospl);
2082 return (NO_RESOURCES);
2083 }
2084 dpt_set_target(0, dpt, channel, target, lun, mode,
2085 length, offset, ccb);
2086 return (SUCCESSFULLY_REGISTERED);
2087 } else
2088 return (NOT_REGISTERED);
2089 } else {
2090 if (op == REGISTER_BUFFER) {
2091 if (dpt->buffer_receiver[channel][target][lun] == callback)
2092 return (ALREADY_REGISTERED);
2093 else
2094 return (REGISTERED_TO_ANOTHER);
2095 } else {
2096 if (dpt->buffer_receiver[channel][target][lun] == callback) {
2097 dpt->buffer_receiver[channel][target][lun] = NULL;
2098 ospl = splsoftcam();
2099 dpt_Qpush_free(dpt, ccb);
2100 splx(ospl);
2101 free(dpt->rw_buffer[channel][target][lun], M_DEVBUF);
2102 return (SUCCESSFULLY_REGISTERED);
2103 } else
2104 return (INVALID_CALLBACK);
2105 }
2106
2107 }
2108}
2109
2110/* Return the state of the blinking DPT LED's */
2111u_int8_t
2112dpt_blinking_led(dpt_softc_t * dpt)
2113{
2114 int ndx;
2115 int ospl;
2116 u_int32_t state;
2117 u_int32_t previous;
2118 u_int8_t result;
2119
2120 ospl = splcam();
2121
2122 result = 0;
2123
2124 for (ndx = 0, state = 0, previous = 0;
2125 (ndx < 10) && (state != previous);
2126 ndx++) {
2127 previous = state;
2128 state = dpt_inl(dpt, 1);
2129 }
2130
2131 if ((state == previous) && (state == DPT_BLINK_INDICATOR))
2132 result = dpt_inb(dpt, 5);
2133
2134 splx(ospl);
2135 return (result);
2136}
2137
2138/*
2139 * Execute a command which did not come from the kernel's SCSI layer.
2140 * The only way to map user commands to bus and target is to comply with the
2141 * standard DPT wire-down scheme:
2142 */
2143int
2144dpt_user_cmd(dpt_softc_t * dpt, eata_pt_t * user_cmd,
2145 caddr_t cmdarg, int minor_no)
2146{
2147 dpt_ccb_t *ccb;
2148 void *data;
2149 int channel, target, lun;
2150 int huh;
2151 int result;
2152 int ospl;
2153 int submitted;
2154
2155 data = NULL;
2156 channel = minor2hba(minor_no);
2157 target = minor2target(minor_no);
2158 lun = minor2lun(minor_no);
2159
2160 if ((channel > (dpt->channels - 1))
2161 || (target > dpt->max_id)
2162 || (lun > dpt->max_lun))
2163 return (ENXIO);
2164
2165 if (target == dpt->sc_scsi_link[channel].adapter_targ) {
2166 /* This one is for the controller itself */
2167 if ((user_cmd->eataID[0] != 'E')
2168 || (user_cmd->eataID[1] != 'A')
2169 || (user_cmd->eataID[2] != 'T')
2170 || (user_cmd->eataID[3] != 'A')) {
2171 return (ENXIO);
2172 }
2173 }
2174 /* Get a DPT CCB, so we can prepare a command */
2175 ospl = splsoftcam();
2176
2177 /* Process the free list */
2178 if ((TAILQ_EMPTY(&dpt->free_ccbs)) && dpt_alloc_freelist(dpt)) {
2179 printf("dpt%d ERROR: Cannot allocate any more free CCB's.\n"
2180 " Please try later\n",
2181 dpt->unit);
2182 splx(ospl);
2183 return (EFAULT);
2184 }
2185 /* Now grab the newest CCB */
2186 if ((ccb = dpt_Qpop_free(dpt)) == NULL) {
2187 splx(ospl);
2188 panic("dpt%d: Got a NULL CCB from pop_free()\n", dpt->unit);
2189 } else {
2190 splx(ospl);
2191 /* Clean up the leftover of the previous tenant */
2192 ccb->status = DPT_CCB_STATE_NEW;
2193 }
2194
2195 bcopy((caddr_t) & user_cmd->command_packet, (caddr_t) & ccb->eata_ccb,
2196 sizeof(eata_ccb_t));
2197
2198 /* We do not want to do user specified scatter/gather. Why?? */
2199 if (ccb->eata_ccb.scatter == 1)
2200 return (EINVAL);
2201
2202 ccb->eata_ccb.Auto_Req_Sen = 1;
2203 ccb->eata_ccb.reqlen = htonl(sizeof(struct scsi_sense_data));
2204 ccb->eata_ccb.cp_datalen = htonl(sizeof(ccb->eata_ccb.cp_datalen));
2205 ccb->eata_ccb.cp_dataDMA = htonl(vtophys(ccb->eata_ccb.cp_dataDMA));
2206 ccb->eata_ccb.cp_statDMA = htonl(vtophys(&ccb->eata_ccb.cp_statDMA));
2207 ccb->eata_ccb.cp_reqDMA = htonl(vtophys(&ccb->eata_ccb.cp_reqDMA));
2208 ccb->eata_ccb.cp_viraddr = (u_int32_t) & ccb;
2209
2210 if (ccb->eata_ccb.DataIn || ccb->eata_ccb.DataOut) {
2211 /* Data I/O is involved in this command. Alocate buffer */
2212 if (ccb->eata_ccb.cp_datalen > PAGE_SIZE) {
2213 data = contigmalloc(ccb->eata_ccb.cp_datalen,
2214 M_TEMP, M_WAITOK, 0, ~0,
2215 ccb->eata_ccb.cp_datalen,
2216 0x10000);
2217 } else {
2218 data = malloc(ccb->eata_ccb.cp_datalen, M_TEMP,
2219 M_WAITOK);
2220 }
2221
2222 if (data == NULL) {
2223 printf("dpt%d: Cannot allocate %d bytes "
2224 "for EATA command\n", dpt->unit,
2225 ccb->eata_ccb.cp_datalen);
2226 return (EFAULT);
2227 }
2228#define usr_cmd_DMA (caddr_t)user_cmd->command_packet.cp_dataDMA
2229 if (ccb->eata_ccb.DataIn == 1) {
2230 if (copyin(usr_cmd_DMA,
2231 data, ccb->eata_ccb.cp_datalen) == -1)
2232 return (EFAULT);
2233 }
2234 } else {
2235 /* No data I/O involved here. Make sure the DPT knows that */
2236 ccb->eata_ccb.cp_datalen = 0;
2237 data = NULL;
2238 }
2239
2240 if (ccb->eata_ccb.FWNEST == 1)
2241 ccb->eata_ccb.FWNEST = 0;
2242
2243 if (ccb->eata_ccb.cp_datalen != 0) {
2244 if (dpt_scatter_gather(dpt, ccb, ccb->eata_ccb.cp_datalen,
2245 data) != 0) {
2246 if (data != NULL)
2247 free(data, M_TEMP);
2248 return (EFAULT);
2249 }
2250 }
2251 /**
2252 * We are required to quiet a SCSI bus.
2253 * since we do not queue comands on a bus basis,
2254 * we wait for ALL commands on a controller to complete.
2255 * In the mean time, sched_queue() will not schedule new commands.
2256 */
2257 if ((ccb->eata_ccb.cp_cdb[0] == MULTIFUNCTION_CMD)
2258 && (ccb->eata_ccb.cp_cdb[2] == BUS_QUIET)) {
2259 /* We wait for ALL traffic for this HBa to subside */
2260 ospl = splsoftcam();
2261 dpt->state |= DPT_HA_QUIET;
2262 splx(ospl);
2263
2264 while ((submitted = dpt->submitted_ccbs_count) != 0) {
2265 huh = tsleep((void *) dpt, PCATCH | PRIBIO, "dptqt",
2266 100 * hz);
2267 switch (huh) {
2268 case 0:
2269 /* Wakeup call received */
2270 break;
2271 case EWOULDBLOCK:
2272 /* Timer Expired */
2273 break;
2274 default:
2275 /* anything else */
2276 break;
2277 }
2278 }
2279 }
2280 /* Resume normal operation */
2281 if ((ccb->eata_ccb.cp_cdb[0] == MULTIFUNCTION_CMD)
2282 && (ccb->eata_ccb.cp_cdb[2] == BUS_UNQUIET)) {
2283 ospl = splsoftcam();
2284 dpt->state &= ~DPT_HA_QUIET;
2285 splx(ospl);
2286 }
2287 /**
2288 * Schedule the command and submit it.
2289 * We bypass dpt_sched_queue, as it will block on DPT_HA_QUIET
2290 */
2291 ccb->xs = NULL;
2292 ccb->flags = 0;
2293 ccb->eata_ccb.Auto_Req_Sen = 1; /* We always want this feature */
2294
2295 ccb->transaction_id = ++dpt->commands_processed;
2296 ccb->std_callback = (ccb_callback) dpt_user_cmd_done;
2297 ccb->result = (u_int32_t) & cmdarg;
2298 ccb->data = data;
2299
2300#ifdef DPT_MEASURE_PERFORMANCE
2301 ++dpt->performance.command_count[ccb->eata_ccb.cp_scsi_cmd];
2302 ccb->command_started = microtime_now;
2303#endif
2304 ospl = splcam();
2305 dpt_Qadd_waiting(dpt, ccb);
2306 splx(ospl);
2307
2308 dpt_sched_queue(dpt);
2309
2310 /* Wait for the command to complete */
2311 (void) tsleep((void *) ccb, PCATCH | PRIBIO, "dptucw", 100 * hz);
2312
2313 /* Free allocated memory */
2314 if (data != NULL)
2315 free(data, M_TEMP);
2316
2317 return (0);
2318}
2319
2320static void
2321dpt_user_cmd_done(dpt_softc_t * dpt, int bus, dpt_ccb_t * ccb)
2322{
2323 int ospl = splsoftcam();
2324 u_int32_t result;
2325 caddr_t cmd_arg;
2326
2327 /**
2328 * If Auto Request Sense is on, copyout the sense struct
2329 */
2330#define usr_pckt_DMA (caddr_t)(intptr_t)ntohl(ccb->eata_ccb.cp_reqDMA)
2331#define usr_pckt_len ntohl(ccb->eata_ccb.cp_datalen)
2332 if (ccb->eata_ccb.Auto_Req_Sen == 1) {
2333 if (copyout((caddr_t) & ccb->sense_data, usr_pckt_DMA,
2334 sizeof(struct scsi_sense_data))) {
2335 ccb->result = EFAULT;
2336 dpt_Qpush_free(dpt, ccb);
2337 splx(ospl);
2338 wakeup(ccb);
2339 return;
2340 }
2341 }
2342 /* If DataIn is on, copyout the data */
2343 if ((ccb->eata_ccb.DataIn == 1)
2344 && (ccb->status_packet.hba_stat == HA_NO_ERROR)) {
2345 if (copyout(ccb->data, usr_pckt_DMA, usr_pckt_len)) {
2346 dpt_Qpush_free(dpt, ccb);
2347 ccb->result = EFAULT;
2348
2349 splx(ospl);
2350 wakeup(ccb);
2351 return;
2352 }
2353 }
2354 /* Copyout the status */
2355 result = ccb->status_packet.hba_stat;
2356 cmd_arg = (caddr_t) ccb->result;
2357
2358 if (copyout((caddr_t) & result, cmd_arg, sizeof(result))) {
2359 dpt_Qpush_free(dpt, ccb);
2360 ccb->result = EFAULT;
2361 splx(ospl);
2362 wakeup(ccb);
2363 return;
2364 }
2365 /* Put the CCB back in the freelist */
2366 ccb->state |= DPT_CCB_STATE_COMPLETED;
2367 dpt_Qpush_free(dpt, ccb);
2368
2369 /* Free allocated memory */
2370 splx(ospl);
2371 return;
2372}
2373
2374#ifdef DPT_HANDLE_TIMEOUTS
2375/**
2376 * This function walks down the SUBMITTED queue.
2377 * Every request that is too old gets aborted and marked.
2378 * Since the DPT will complete (interrupt) immediately (what does that mean?),
2379 * We just walk the list, aborting old commands and marking them as such.
2380 * The dpt_complete function will get rid of the that were interrupted in the
2381 * normal manner.
2382 *
2383 * This function needs to run at splcam(), as it interacts with the submitted
2384 * queue, as well as the completed and free queues. Just like dpt_intr() does.
2385 * To run it at any ISPL other than that of dpt_intr(), will mean that dpt_intr
2386 * willbe able to pre-empt it, grab a transaction in progress (towards
2387 * destruction) and operate on it. The state of this transaction will be not
2388 * very clear.
2389 * The only other option, is to lock it only as long as necessary but have
2390 * dpt_intr() spin-wait on it. In a UP environment this makes no sense and in
2391 * a SMP environment, the advantage is dubvious for a function that runs once
2392 * every ten seconds for few microseconds and, on systems with healthy
2393 * hardware, does not do anything anyway.
2394 */
2395
2396static void
2397dpt_handle_timeouts(dpt_softc_t * dpt)
2398{
2399 dpt_ccb_t *ccb;
2400 int ospl;
2401
2402 ospl = splcam();
2403
2404 if (dpt->state & DPT_HA_TIMEOUTS_ACTIVE) {
2405 printf("dpt%d WARNING: Timeout Handling Collision\n",
2406 dpt->unit);
2407 splx(ospl);
2408 return;
2409 }
2410 dpt->state |= DPT_HA_TIMEOUTS_ACTIVE;
2411
2412 /* Loop through the entire submitted queue, looking for lost souls */
2413 for (ccb = TAILQ_FIRST(&dpt->submitted_ccbs);
2414 ccb != NULL;
2415 ccb = TAILQ_NEXT(ccb, links)) {
2416 struct scsi_xfer *xs;
2417 u_int32_t age, max_age;
2418
2419 xs = ccb->xs;
2420 age = dpt_time_delta(ccb->command_started, microtime_now);
2421
2422#define TenSec 10000000
2423
2424 if (xs == NULL) { /* Local, non-kernel call */
2425 max_age = TenSec;
2426 } else {
2427 max_age = (((xs->timeout * (dpt->submitted_ccbs_count
2428 + DPT_TIMEOUT_FACTOR))
2429 > TenSec)
2430 ? (xs->timeout * (dpt->submitted_ccbs_count
2431 + DPT_TIMEOUT_FACTOR))
2432 : TenSec);
2433 }
2434
2435 /*
2436 * If a transaction is marked lost and is TWICE as old as we
2437 * care, then, and only then do we destroy it!
2438 */
2439 if (ccb->state & DPT_CCB_STATE_MARKED_LOST) {
2440 /* Remember who is next */
2441 if (age > (max_age * 2)) {
2442 dpt_Qremove_submitted(dpt, ccb);
2443 ccb->state &= ~DPT_CCB_STATE_MARKED_LOST;
2444 ccb->state |= DPT_CCB_STATE_ABORTED;
2445#define cmd_name scsi_cmd_name(ccb->eata_ccb.cp_scsi_cmd)
2446 if (ccb->retries++ > DPT_RETRIES) {
2447 printf("dpt%d ERROR: Destroying stale "
2448 "%d (%s)\n"
2449 " on "
2450 "c%db%dt%du%d (%d/%d)\n",
2451 dpt->unit, ccb->transaction_id,
2452 cmd_name,
2453 dpt->unit,
2454 ccb->eata_ccb.cp_channel,
2455 ccb->eata_ccb.cp_id,
2456 ccb->eata_ccb.cp_LUN, age,
2457 ccb->retries);
2458#define send_ccb &ccb->eata_ccb
2459#define ESA EATA_SPECIFIC_ABORT
2460 (void) dpt_send_immediate(dpt,
2461 send_ccb,
2462 ESA,
2463 0, 0);
2464 dpt_Qpush_free(dpt, ccb);
2465
2466 /* The SCSI layer should re-try */
2467 xs->error |= XS_TIMEOUT;
2468 xs->flags |= SCSI_ITSDONE;
2469 scsi_done(xs);
2470 } else {
2471 printf("dpt%d ERROR: Stale %d (%s) on "
2472 "c%db%dt%du%d (%d)\n"
2473 " gets another "
2474 "chance(%d/%d)\n",
2475 dpt->unit, ccb->transaction_id,
2476 cmd_name,
2477 dpt->unit,
2478 ccb->eata_ccb.cp_channel,
2479 ccb->eata_ccb.cp_id,
2480 ccb->eata_ccb.cp_LUN,
2481 age, ccb->retries, DPT_RETRIES);
2482
2483 dpt_Qpush_waiting(dpt, ccb);
2484 dpt_sched_queue(dpt);
2485 }
2486 }
2487 } else {
2488 /*
2489 * This is a transaction that is not to be destroyed
2490 * (yet) But it is too old for our liking. We wait as
2491 * long as the upper layer thinks. Not really, we
2492 * multiply that by the number of commands in the
2493 * submitted queue + 1.
2494 */
2495 if (!(ccb->state & DPT_CCB_STATE_MARKED_LOST) &&
2496 (age != ~0) && (age > max_age)) {
2497 printf("dpt%d ERROR: Marking %d (%s) on "
2498 "c%db%dt%du%d \n"
2499 " as late after %dusec\n",
2500 dpt->unit, ccb->transaction_id,
2501 cmd_name,
2502 dpt->unit, ccb->eata_ccb.cp_channel,
2503 ccb->eata_ccb.cp_id,
2504 ccb->eata_ccb.cp_LUN, age);
2505 ccb->state |= DPT_CCB_STATE_MARKED_LOST;
2506 }
2507 }
2508 }
2509
2510 dpt->state &= ~DPT_HA_TIMEOUTS_ACTIVE;
2511 splx(ospl);
2512}
2513
2514static void
2515dpt_timeout(void *arg)
2516{
2517 dpt_softc_t *dpt = (dpt_softc_t *) arg;
2518
2519 if (!(dpt->state & DPT_HA_TIMEOUTS_ACTIVE))
2520 dpt_handle_timeouts(dpt);
2521
2522 timeout(dpt_timeout, (caddr_t) dpt, hz * 10);
2523}
2524
2525#endif /* DPT_HANDLE_TIMEOUTS */
2526
2527#endif