.Pp before .Sh is not needed.
[dragonfly.git] / sys / dev / disk / aic / aic.c
CommitLineData
984263bc
MD
1/*-
2 * Copyright (c) 1999 Luoqi Chen.
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 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: src/sys/dev/aic/aic.c,v 1.8 2000/01/14 23:42:35 imp Exp $
15a28004 27 * $DragonFly: src/sys/dev/disk/aic/aic.c,v 1.11 2008/01/02 11:41:52 hasso Exp $
984263bc
MD
28 */
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/malloc.h>
33#include <sys/buf.h>
34#include <sys/kernel.h>
35#include <sys/sysctl.h>
36#include <sys/bus.h>
1f7ab7c9 37#include <sys/thread2.h>
984263bc 38
984263bc
MD
39#include <machine/clock.h>
40
1f2de5d4
MD
41#include <bus/cam/cam.h>
42#include <bus/cam/cam_ccb.h>
43#include <bus/cam/cam_sim.h>
44#include <bus/cam/cam_xpt_sim.h>
45#include <bus/cam/cam_debug.h>
984263bc 46
1f2de5d4 47#include <bus/cam/scsi/scsi_message.h>
984263bc 48
1f2de5d4
MD
49#include "aic6360reg.h"
50#include "aicvar.h"
984263bc 51
38e94a25
RG
52static void aic_action (struct cam_sim *sim, union ccb *ccb);
53static void aic_execute_scb (void *arg, bus_dma_segment_t *dm_segs,
54 int nseg, int error);
55static void aic_start (struct aic_softc *aic);
56static void aic_select (struct aic_softc *aic);
57static void aic_selected (struct aic_softc *aic);
58static void aic_reselected (struct aic_softc *aic);
59static void aic_reconnect (struct aic_softc *aic, int tag);
60static void aic_cmd (struct aic_softc *aic);
61static void aic_msgin (struct aic_softc *aic);
62static void aic_handle_msgin (struct aic_softc *aic);
63static void aic_msgout (struct aic_softc *aic);
64static void aic_datain (struct aic_softc *aic);
65static void aic_dataout (struct aic_softc *aic);
66static void aic_done (struct aic_softc *aic, struct aic_scb *scb);
67static void aic_poll (struct cam_sim *sim);
68static void aic_timeout (void *arg);
69static void aic_scsi_reset (struct aic_softc *aic);
70static void aic_chip_reset (struct aic_softc *aic);
71static void aic_reset (struct aic_softc *aic, int initiate_reset);
984263bc
MD
72
73devclass_t aic_devclass;
74
75static struct aic_scb *free_scbs;
76
77static struct aic_scb *
78aic_get_scb(struct aic_softc *aic)
79{
80 struct aic_scb *scb;
dee48646
JS
81
82 crit_enter();
83
984263bc
MD
84 if ((scb = free_scbs) != NULL)
85 free_scbs = (struct aic_scb *)free_scbs->ccb;
dee48646
JS
86
87 crit_exit();
984263bc
MD
88 return (scb);
89}
90
91static void
92aic_free_scb(struct aic_softc *aic, struct aic_scb *scb)
93{
dee48646
JS
94 crit_enter();
95
984263bc
MD
96 if ((aic->flags & AIC_RESOURCE_SHORTAGE) != 0 &&
97 (scb->ccb->ccb_h.status & CAM_RELEASE_SIMQ) == 0) {
98 scb->ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
99 aic->flags &= ~AIC_RESOURCE_SHORTAGE;
100 }
101 scb->flags = 0;
102 scb->ccb = (union ccb *)free_scbs;
103 free_scbs = scb;
dee48646
JS
104
105 crit_exit();
984263bc
MD
106}
107
108static void
109aic_action(struct cam_sim *sim, union ccb *ccb)
110{
111 struct aic_softc *aic;
984263bc
MD
112
113 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("aic_action\n"));
114
115 aic = (struct aic_softc *)cam_sim_softc(sim);
116
117 switch (ccb->ccb_h.func_code) {
118 case XPT_SCSI_IO: /* Execute the requested I/O operation */
119 case XPT_RESET_DEV: /* Bus Device Reset the specified SCSI device */
120 {
121 struct aic_scb *scb;
122
123 if ((scb = aic_get_scb(aic)) == NULL) {
dee48646 124 crit_enter();
984263bc 125 aic->flags |= AIC_RESOURCE_SHORTAGE;
dee48646 126 crit_exit();
984263bc
MD
127 xpt_freeze_simq(aic->sim, /*count*/1);
128 ccb->ccb_h.status = CAM_REQUEUE_REQ;
129 xpt_done(ccb);
130 return;
131 }
132
133 scb->ccb = ccb;
134 ccb->ccb_h.ccb_scb_ptr = scb;
135 ccb->ccb_h.ccb_aic_ptr = aic;
136
137 scb->target = ccb->ccb_h.target_id;
138 scb->lun = ccb->ccb_h.target_lun;
139
140 if (ccb->ccb_h.func_code == XPT_SCSI_IO) {
141 scb->cmd_len = ccb->csio.cdb_len;
142 if (ccb->ccb_h.flags & CAM_CDB_POINTER) {
143 if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
144 ccb->ccb_h.status = CAM_REQ_INVALID;
145 aic_free_scb(aic, scb);
146 xpt_done(ccb);
147 return;
148 }
149 scb->cmd_ptr = ccb->csio.cdb_io.cdb_ptr;
150 } else {
151 scb->cmd_ptr = ccb->csio.cdb_io.cdb_bytes;
152 }
153 if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
154 if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) ||
155 (ccb->ccb_h.flags & CAM_DATA_PHYS)) {
156 ccb->ccb_h.status = CAM_REQ_INVALID;
157 aic_free_scb(aic, scb);
158 xpt_done(ccb);
159 return;
160 }
161 scb->data_ptr = ccb->csio.data_ptr;
162 scb->data_len = ccb->csio.dxfer_len;
163 } else {
164 scb->data_ptr = NULL;
165 scb->data_len = 0;
166 }
167 aic_execute_scb(scb, NULL, 0, 0);
168 } else {
169 scb->flags |= SCB_DEVICE_RESET;
170 aic_execute_scb(scb, NULL, 0, 0);
171 }
172 break;
173 }
174 case XPT_SET_TRAN_SETTINGS:
175 {
f19fcfb0
PA
176 struct ccb_trans_settings *cts = cts = &ccb->cts;
177 struct aic_tinfo *ti = &aic->tinfo[ccb->ccb_h.target_id];
178#ifdef CAM_NEW_TRAN_CODE
179 struct ccb_trans_settings_scsi *scsi =
180 &cts->proto_specific.scsi;
181 struct ccb_trans_settings_spi *spi =
182 &cts->xport_specific.spi;
984263bc 183
dee48646 184 crit_enter();
984263bc 185
f19fcfb0
PA
186 if ((spi->valid & CTS_SPI_VALID_DISC) != 0 &&
187 (aic->flags & AIC_DISC_ENABLE) != 0) {
188 if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
189 ti->flags |= TINFO_DISC_ENB;
190 else
191 ti->flags &= ~TINFO_DISC_ENB;
192 }
193
194 if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
195 if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
196 ti->flags |= TINFO_TAG_ENB;
197 else
198 ti->flags &= ~TINFO_TAG_ENB;
199 }
200
201 if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0) {
202 ti->goal.period = spi->sync_period;
203
204 if (ti->goal.period > aic->min_period) {
205 ti->goal.period = 0;
206 ti->goal.offset = 0;
207 } else if (ti->goal.period < aic->max_period)
208 ti->goal.period = aic->max_period;
209 }
210
211 if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0) {
212 ti->goal.offset = spi->sync_offset;
213 if (ti->goal.offset == 0)
214 ti->goal.period = 0;
215 else if (ti->goal.offset > AIC_SYNC_OFFSET)
216 ti->goal.offset = AIC_SYNC_OFFSET;
217 }
218
219 if ((ti->goal.period != ti->current.period)
220 || (ti->goal.offset != ti->current.offset))
221 ti->flags |= TINFO_SDTR_NEGO;
222
223 crit_exit();
224#else
225 crit_enter();
984263bc
MD
226 if ((cts->valid & CCB_TRANS_DISC_VALID) != 0 &&
227 (aic->flags & AIC_DISC_ENABLE) != 0) {
228 if ((cts->flags & CCB_TRANS_DISC_ENB) != 0)
229 ti->flags |= TINFO_DISC_ENB;
230 else
231 ti->flags &= ~TINFO_DISC_ENB;
232 }
233
234 if ((cts->valid & CCB_TRANS_TQ_VALID) != 0) {
235 if ((cts->flags & CCB_TRANS_TAG_ENB) != 0)
236 ti->flags |= TINFO_TAG_ENB;
237 else
238 ti->flags &= ~TINFO_TAG_ENB;
239 }
240
241 if ((cts->valid & CCB_TRANS_SYNC_RATE_VALID) != 0) {
242 ti->goal.period = cts->sync_period;
243 if (ti->goal.period != ti->current.period)
244 ti->flags |= TINFO_SDTR_NEGO;
245 }
246
247 if ((cts->valid & CCB_TRANS_SYNC_OFFSET_VALID) != 0) {
248 ti->goal.offset = cts->sync_offset;
249 if (ti->goal.offset != ti->current.offset)
250 ti->flags |= TINFO_SDTR_NEGO;
251 }
252
dee48646 253 crit_exit();
f19fcfb0 254#endif
984263bc
MD
255 ccb->ccb_h.status = CAM_REQ_CMP;
256 xpt_done(ccb);
257 break;
258 }
259 case XPT_GET_TRAN_SETTINGS:
260 {
f19fcfb0
PA
261 struct ccb_trans_settings *cts = &ccb->cts;
262 struct aic_tinfo *ti = &aic->tinfo[ccb->ccb_h.target_id];
263#ifdef CAM_NEW_TRAN_CODE
264 struct ccb_trans_settings_scsi *scsi =
265 &cts->proto_specific.scsi;
266 struct ccb_trans_settings_spi *spi =
267 &cts->xport_specific.spi;
268
269 cts->protocol = PROTO_SCSI;
270 cts->protocol_version = SCSI_REV_2;
271 cts->transport = XPORT_SPI;
272 cts->transport_version = 2;
273 scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
274 spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
984263bc 275
dee48646 276 crit_enter();
f19fcfb0
PA
277 if ((ti->flags & TINFO_DISC_ENB) != 0)
278 spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
279 if ((ti->flags & TINFO_TAG_ENB) != 0)
280 scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
984263bc 281
f19fcfb0
PA
282 if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
283 spi->sync_period = ti->current.period;
284 spi->sync_offset = ti->current.offset;
285 } else {
286 spi->sync_period = ti->user.period;
287 spi->sync_offset = ti->user.offset;
288 }
15a28004 289 crit_exit();
f19fcfb0
PA
290
291 spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
292 spi->valid = CTS_SPI_VALID_SYNC_RATE
293 | CTS_SPI_VALID_SYNC_OFFSET
294 | CTS_SPI_VALID_BUS_WIDTH
295 | CTS_SPI_VALID_DISC;
296 scsi->valid = CTS_SCSI_VALID_TQ;
297#else
298 crit_enter();
984263bc
MD
299 cts->flags &= ~(CCB_TRANS_DISC_ENB|CCB_TRANS_TAG_ENB);
300 if ((ti->flags & TINFO_DISC_ENB) != 0)
301 cts->flags |= CCB_TRANS_DISC_ENB;
302 if ((ti->flags & TINFO_TAG_ENB) != 0)
303 cts->flags |= CCB_TRANS_TAG_ENB;
304
305 if ((cts->flags & CCB_TRANS_CURRENT_SETTINGS) != 0) {
306 cts->sync_period = ti->current.period;
307 cts->sync_offset = ti->current.offset;
308 } else {
309 cts->sync_period = ti->user.period;
310 cts->sync_offset = ti->user.offset;
311 }
312 cts->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
313
dee48646 314 crit_exit();
984263bc
MD
315
316 cts->valid = CCB_TRANS_SYNC_RATE_VALID
317 | CCB_TRANS_SYNC_OFFSET_VALID
318 | CCB_TRANS_BUS_WIDTH_VALID
319 | CCB_TRANS_DISC_VALID
320 | CCB_TRANS_TQ_VALID;
f19fcfb0 321#endif
984263bc
MD
322
323 ccb->ccb_h.status = CAM_REQ_CMP;
324 xpt_done(ccb);
325 break;
326 }
327 case XPT_CALC_GEOMETRY:
328 {
329 struct ccb_calc_geometry *ccg;
330 u_int32_t size_mb;
331 u_int32_t secs_per_cylinder;
332 int extended = 0;
333
334 ccg = &ccb->ccg;
335 size_mb = ccg->volume_size
336 / ((1024L * 1024L) / ccg->block_size);
337
338 if (size_mb >= 1024 && extended) {
339 ccg->heads = 255;
340 ccg->secs_per_track = 63;
341 } else {
342 ccg->heads = 64;
343 ccg->secs_per_track = 32;
344 }
345 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
346 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
347 ccb->ccb_h.status = CAM_REQ_CMP;
348 xpt_done(ccb);
349 break;
350 }
351 case XPT_RESET_BUS: /* Reset the specified SCSI bus */
352 aic_reset(aic, /*initiate_reset*/TRUE);
353 ccb->ccb_h.status = CAM_REQ_CMP;
354 xpt_done(ccb);
355 break;
356 case XPT_PATH_INQ: /* Path routing inquiry */
357 {
358 struct ccb_pathinq *cpi = &ccb->cpi;
359
360 cpi->version_num = 1; /* XXX??? */
361 cpi->hba_inquiry = PI_SDTR_ABLE | PI_TAG_ABLE;
362 cpi->target_sprt = 0;
363 cpi->hba_misc = 0;
364 cpi->hba_eng_cnt = 0;
365 cpi->max_target = 7;
366 cpi->max_lun = 7;
367 cpi->initiator_id = aic->initiator;
368 cpi->bus_id = cam_sim_bus(sim);
369 cpi->base_transfer_speed = 3300;
370 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
371 strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
372 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
373 cpi->unit_number = cam_sim_unit(sim);
f19fcfb0
PA
374#ifdef CAM_NEW_TRAN_CODE
375 cpi->transport = XPORT_SPI;
376 cpi->transport_version = 2;
377 cpi->protocol = PROTO_SCSI;
378 cpi->protocol_version = SCSI_REV_2;
379#endif
984263bc
MD
380 cpi->ccb_h.status = CAM_REQ_CMP;
381 xpt_done(ccb);
382 break;
383 }
384 default:
385 ccb->ccb_h.status = CAM_REQ_INVALID;
386 xpt_done(ccb);
387 break;
388 }
389}
390
391static void
392aic_execute_scb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
393{
394 struct aic_scb *scb = (struct aic_scb *)arg;
395 union ccb *ccb = scb->ccb;
396 struct aic_softc *aic = (struct aic_softc *)ccb->ccb_h.ccb_aic_ptr;
984263bc 397
dee48646 398 crit_enter();
984263bc
MD
399
400 if (ccb->ccb_h.status != CAM_REQ_INPROG) {
dee48646 401 crit_exit();
984263bc
MD
402 aic_free_scb(aic, scb);
403 xpt_done(ccb);
404 return;
405 }
406
407 scb->flags |= SCB_ACTIVE;
408 ccb->ccb_h.status |= CAM_SIM_QUEUED;
409 TAILQ_INSERT_TAIL(&aic->pending_ccbs, &ccb->ccb_h, sim_links.tqe);
410
ddcafce9
JS
411 callout_reset(&ccb->ccb_h.timeout_ch, (ccb->ccb_h.timeout * hz) / 1000,
412 aic_timeout, scb);
984263bc
MD
413
414 aic_start(aic);
dee48646 415 crit_exit();
984263bc
MD
416}
417
418/*
419 * Start another command if the controller is not busy.
420 */
421static void
422aic_start(struct aic_softc *aic)
423{
424 struct ccb_hdr *ccb_h;
425 struct aic_tinfo *ti;
426
427 if (aic->state != AIC_IDLE)
428 return;
429
430 TAILQ_FOREACH(ccb_h, &aic->pending_ccbs, sim_links.tqe) {
431 ti = &aic->tinfo[ccb_h->target_id];
432 if ((ti->lubusy & (1 << ccb_h->target_lun)) == 0) {
433 TAILQ_REMOVE(&aic->pending_ccbs, ccb_h, sim_links.tqe);
434 aic->nexus = (struct aic_scb *)ccb_h->ccb_scb_ptr;
435 aic_select(aic);
436 return;
437 }
438 }
439
440 CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_start: idle\n"));
441
442 aic_outb(aic, SIMODE0, ENSELDI);
443 aic_outb(aic, SIMODE1, ENSCSIRST);
444 aic_outb(aic, SCSISEQ, ENRESELI);
445}
446
447/*
448 * Start a selection.
449 */
450static void
451aic_select(struct aic_softc *aic)
452{
453 struct aic_scb *scb = aic->nexus;
454
455 CAM_DEBUG(scb->ccb->ccb_h.path, CAM_DEBUG_TRACE,
456 ("aic_select - ccb %p\n", scb->ccb));
457
458 aic->state = AIC_SELECTING;
459
460 aic_outb(aic, DMACNTRL1, 0);
461 aic_outb(aic, SCSIID, aic->initiator << OID_S | scb->target);
462 aic_outb(aic, SXFRCTL1, STIMO_256ms | ENSTIMER |
463 (aic->flags & AIC_PARITY_ENABLE ? ENSPCHK : 0));
464
465 aic_outb(aic, SIMODE0, ENSELDI|ENSELDO);
466 aic_outb(aic, SIMODE1, ENSCSIRST|ENSELTIMO);
467 aic_outb(aic, SCSISEQ, ENRESELI|ENSELO|ENAUTOATNO);
468}
469
470/*
471 * We have successfully selected a target, prepare for the information
472 * transfer phases.
473 */
474static void
475aic_selected(struct aic_softc *aic)
476{
477 struct aic_scb *scb = aic->nexus;
478 union ccb *ccb = scb->ccb;
479 struct aic_tinfo *ti = &aic->tinfo[scb->target];
480
481 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
482 ("aic_selected - ccb %p\n", ccb));
483
484 aic->state = AIC_HASNEXUS;
485
486 if (scb->flags & SCB_DEVICE_RESET) {
487 aic->msg_buf[0] = MSG_BUS_DEV_RESET;
488 aic->msg_len = 1;
489 aic->msg_outq = AIC_MSG_MSGBUF;
490 } else {
491 aic->msg_outq = AIC_MSG_IDENTIFY;
492 if ((ti->flags & TINFO_TAG_ENB) != 0 &&
493 (ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0)
494 aic->msg_outq |= AIC_MSG_TAG_Q;
495 else
496 ti->lubusy |= 1 << scb->lun;
497 if ((ti->flags & TINFO_SDTR_NEGO) != 0)
498 aic->msg_outq |= AIC_MSG_SDTR;
499 }
500
501 aic_outb(aic, CLRSINT0, CLRSELDO);
502 aic_outb(aic, CLRSINT1, CLRBUSFREE);
503 aic_outb(aic, SCSISEQ, ENAUTOATNP);
504 aic_outb(aic, SIMODE0, 0);
505 aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
506 aic_outb(aic, SCSIRATE, ti->scsirate);
507}
508
509/*
510 * We are re-selected by a target, save the target id and wait for the
511 * target to further identify itself.
512 */
513static void
514aic_reselected(struct aic_softc *aic)
515{
516 u_int8_t selid;
517
518 CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_reselected\n"));
519
520 /*
521 * If we have started a selection, it must have lost out in
522 * the arbitration, put the command back to the pending queue.
523 */
524 if (aic->nexus) {
525 TAILQ_INSERT_HEAD(&aic->pending_ccbs,
526 &aic->nexus->ccb->ccb_h, sim_links.tqe);
527 aic->nexus = NULL;
528 }
529
530 selid = aic_inb(aic, SELID) & ~(1 << aic->initiator);
531 if (selid & (selid - 1)) {
532 /* this should never have happened */
e3869ec7 533 kprintf("aic_reselected: invalid selid %x\n", selid);
984263bc
MD
534 aic_reset(aic, /*initiate_reset*/TRUE);
535 return;
536 }
537
538 aic->state = AIC_RESELECTED;
539 aic->target = ffs(selid) - 1;
540 aic->lun = -1;
541
542 aic_outb(aic, CLRSINT0, CLRSELDI);
543 aic_outb(aic, CLRSINT1, CLRBUSFREE);
544 aic_outb(aic, SIMODE0, 0);
545 aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
546 aic_outb(aic, SCSISEQ, ENAUTOATNP);
547 aic_outb(aic, SCSIRATE, aic->tinfo[aic->target].scsirate);
548}
549
550/*
551 * Raise ATNO to signal the target that we have a message for it.
552 */
553static __inline void
554aic_sched_msgout(struct aic_softc *aic, u_int8_t msg)
555{
556 if (msg) {
557 aic->msg_buf[0] = msg;
558 aic->msg_len = 1;
559 }
560 aic->msg_outq |= AIC_MSG_MSGBUF;
561 aic_outb(aic, SCSISIGO, aic_inb(aic, SCSISIGI) | ATNO);
562}
563
564/*
565 * Wait for SPIORDY (SCSI PIO ready) flag, or a phase change.
566 */
567static __inline int
568aic_spiordy(struct aic_softc *aic)
569{
570 while (!(aic_inb(aic, DMASTAT) & INTSTAT) &&
571 !(aic_inb(aic, SSTAT0) & SPIORDY))
572 ;
573 return !(aic_inb(aic, DMASTAT) & INTSTAT);
574}
575
576/*
577 * Reestablish a disconnected nexus.
578 */
579void
580aic_reconnect(struct aic_softc *aic, int tag)
581{
582 struct aic_scb *scb;
583 struct ccb_hdr *ccb_h;
584
585 CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_reconnect\n"));
586
587 /* Find the nexus */
588 TAILQ_FOREACH(ccb_h, &aic->nexus_ccbs, sim_links.tqe) {
589 scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
590 if (scb->target == aic->target && scb->lun == aic->lun &&
591 (tag == -1 || scb->tag == tag))
592 break;
593 }
594
595 /* ABORT if nothing is found */
596 if (!ccb_h) {
597 if (tag == -1)
598 aic_sched_msgout(aic, MSG_ABORT);
599 else
600 aic_sched_msgout(aic, MSG_ABORT_TAG);
601 xpt_async(AC_UNSOL_RESEL, aic->path, NULL);
602 return;
603 }
604
605 /* Reestablish the nexus */
606 TAILQ_REMOVE(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
607 aic->nexus = scb;
608 scb->flags &= ~SCB_DISCONNECTED;
609 aic->state = AIC_HASNEXUS;
610}
611
612/*
613 * Read messages.
614 */
615static void
616aic_msgin(struct aic_softc *aic)
617{
618 int msglen;
619
620 CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_msgin\n"));
621
622 aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
623 aic_outb(aic, SXFRCTL0, CHEN|SPIOEN);
624
625 aic->flags &= ~AIC_DROP_MSGIN;
626 aic->msg_len = 0;
627 do {
628 /*
629 * If a parity error is detected, drop the remaining
630 * bytes and inform the target so it could resend
631 * the messages.
632 */
633 if (aic_inb(aic, SSTAT1) & SCSIPERR) {
634 aic_outb(aic, CLRSINT1, CLRSCSIPERR);
635 aic->flags |= AIC_DROP_MSGIN;
636 aic_sched_msgout(aic, MSG_PARITY_ERROR);
637 }
638 if ((aic->flags & AIC_DROP_MSGIN)) {
639 aic_inb(aic, SCSIDAT);
640 continue;
641 }
642 /* read the message byte without ACKing on it */
643 aic->msg_buf[aic->msg_len++] = aic_inb(aic, SCSIBUS);
644 if (aic->msg_buf[0] == MSG_EXTENDED) {
645 if (aic->msg_len < 2) {
646 (void) aic_inb(aic, SCSIDAT);
647 continue;
648 }
649 switch (aic->msg_buf[2]) {
650 case MSG_EXT_SDTR:
651 msglen = MSG_EXT_SDTR_LEN;
652 break;
653 case MSG_EXT_WDTR:
654 msglen = MSG_EXT_WDTR_LEN;
655 break;
656 default:
657 msglen = 0;
658 break;
659 }
660 if (aic->msg_buf[1] != msglen) {
661 aic->flags |= AIC_DROP_MSGIN;
662 aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
663 }
664 msglen += 2;
665 } else if (aic->msg_buf[0] >= 0x20 && aic->msg_buf[0] <= 0x2f)
666 msglen = 2;
667 else
668 msglen = 1;
669 /*
670 * If we have a complete message, handle it before the final
671 * ACK (in case we decide to reject the message).
672 */
673 if (aic->msg_len == msglen) {
674 aic_handle_msgin(aic);
675 aic->msg_len = 0;
676 }
677 /* ACK on the message byte */
678 (void) aic_inb(aic, SCSIDAT);
679 } while (aic_spiordy(aic));
680
681 aic_outb(aic, SXFRCTL0, CHEN);
682 aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
683}
684
685/*
686 * Handle a message.
687 */
688static void
689aic_handle_msgin(struct aic_softc *aic)
690{
691 struct aic_scb *scb;
692 struct ccb_hdr *ccb_h;
693 struct aic_tinfo *ti;
694 struct ccb_trans_settings neg;
f19fcfb0
PA
695#ifdef CAM_NEW_TRAN_CODE
696 struct ccb_trans_settings_spi *spi = &neg.xport_specific.spi;
697#endif
984263bc
MD
698
699 if (aic->state == AIC_RESELECTED) {
700 if (!MSG_ISIDENTIFY(aic->msg_buf[0])) {
701 aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
702 return;
703 }
704 aic->lun = aic->msg_buf[0] & MSG_IDENTIFY_LUNMASK;
705 if (aic->tinfo[aic->target].lubusy & (1 << aic->lun))
706 aic_reconnect(aic, -1);
707 else
708 aic->state = AIC_RECONNECTING;
709 return;
710 }
711
712 if (aic->state == AIC_RECONNECTING) {
713 if (aic->msg_buf[0] != MSG_SIMPLE_Q_TAG) {
714 aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
715 return;
716 }
717 aic_reconnect(aic, aic->msg_buf[1]);
718 return;
719 }
720
721 switch (aic->msg_buf[0]) {
722 case MSG_CMDCOMPLETE: {
723 struct ccb_scsiio *csio;
724 scb = aic->nexus;
725 ccb_h = &scb->ccb->ccb_h;
726 csio = &scb->ccb->csio;
727 if ((scb->flags & SCB_SENSE) != 0) {
728 /* auto REQUEST SENSE command */
729 scb->flags &= ~SCB_SENSE;
730 csio->sense_resid = scb->data_len;
731 if (scb->status == SCSI_STATUS_OK) {
732 ccb_h->status |=
733 CAM_SCSI_STATUS_ERROR|CAM_AUTOSNS_VALID;
734 /*scsi_sense_print(csio);*/
735 } else {
736 ccb_h->status |= CAM_AUTOSENSE_FAIL;
e3869ec7 737 kprintf("ccb %p sense failed %x\n",
984263bc
MD
738 ccb_h, scb->status);
739 }
740 } else {
741 csio->scsi_status = scb->status;
742 csio->resid = scb->data_len;
743 if (scb->status == SCSI_STATUS_OK) {
744 /* everything goes well */
745 ccb_h->status |= CAM_REQ_CMP;
746 } else if ((ccb_h->flags & CAM_DIS_AUTOSENSE) == 0 &&
747 (csio->scsi_status == SCSI_STATUS_CHECK_COND ||
748 csio->scsi_status == SCSI_STATUS_CMD_TERMINATED)) {
749 /* try to retrieve sense information */
750 scb->flags |= SCB_SENSE;
751 aic->flags |= AIC_BUSFREE_OK;
752 return;
753 } else
754 ccb_h->status |= CAM_SCSI_STATUS_ERROR;
755 }
756 aic_done(aic, scb);
757 aic->flags |= AIC_BUSFREE_OK;
758 break;
759 }
760 case MSG_EXTENDED:
761 switch (aic->msg_buf[2]) {
762 case MSG_EXT_SDTR:
763 scb = aic->nexus;
764 ti = &aic->tinfo[scb->target];
765 if (ti->flags & TINFO_SDTR_SENT) {
766 ti->current.period = aic->msg_buf[3];
767 ti->current.offset = aic->msg_buf[4];
768 } else {
769 ti->current.period = aic->msg_buf[3] =
770 max(ti->goal.period, aic->msg_buf[3]);
771 ti->current.offset = aic->msg_buf[4] =
772 min(ti->goal.offset, aic->msg_buf[4]);
773 /*
774 * The target initiated the negotiation,
775 * send back a response.
776 */
777 aic_sched_msgout(aic, 0);
778 }
779 ti->flags &= ~(TINFO_SDTR_SENT|TINFO_SDTR_NEGO);
780 ti->scsirate = ti->current.offset ? ti->current.offset |
781 ((ti->current.period * 4 + 49) / 50 - 2) << 4 : 0;
782 aic_outb(aic, SCSIRATE, ti->scsirate);
f19fcfb0
PA
783 memset(&neg, 0, sizeof (neg));
784#ifdef CAM_NEW_TRAN_CODE
785 neg.protocol = PROTO_SCSI;
786 neg.protocol_version = SCSI_REV_2;
787 neg.transport = XPORT_SPI;
788 neg.transport_version = 2;
789 spi->sync_period = ti->goal.period = ti->current.period;
790 spi->sync_offset = ti->goal.offset = ti->current.offset;
791 spi->valid = CTS_SPI_VALID_SYNC_RATE
792 | CTS_SPI_VALID_SYNC_OFFSET;
793#else
984263bc
MD
794 neg.sync_period = ti->goal.period = ti->current.period;
795 neg.sync_offset = ti->goal.offset = ti->current.offset;
796 neg.valid = CCB_TRANS_SYNC_RATE_VALID
797 | CCB_TRANS_SYNC_OFFSET_VALID;
f19fcfb0 798#endif
984263bc
MD
799 ccb_h = &scb->ccb->ccb_h;
800 xpt_setup_ccb(&neg.ccb_h, ccb_h->path, 1);
801 xpt_async(AC_TRANSFER_NEG, ccb_h->path, &neg);
802 break;
803 case MSG_EXT_WDTR:
804 default:
805 aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
806 break;
807 }
808 break;
809 case MSG_DISCONNECT:
810 scb = aic->nexus;
811 ccb_h = &scb->ccb->ccb_h;
812 TAILQ_INSERT_TAIL(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
813 scb->flags |= SCB_DISCONNECTED;
814 aic->flags |= AIC_BUSFREE_OK;
815 aic->nexus = NULL;
816 CAM_DEBUG(ccb_h->path, CAM_DEBUG_TRACE, ("disconnected\n"));
817 break;
818 case MSG_MESSAGE_REJECT:
819 switch (aic->msg_outq & -aic->msg_outq) {
820 case AIC_MSG_TAG_Q:
821 scb = aic->nexus;
822 ti = &aic->tinfo[scb->target];
823 ti->flags &= ~TINFO_TAG_ENB;
824 ti->lubusy |= 1 << scb->lun;
825 break;
826 case AIC_MSG_SDTR:
827 scb = aic->nexus;
828 ti = &aic->tinfo[scb->target];
829 ti->current.period = ti->goal.period = 0;
830 ti->current.offset = ti->goal.offset = 0;
831 ti->flags &= ~(TINFO_SDTR_SENT|TINFO_SDTR_NEGO);
832 ti->scsirate = 0;
833 aic_outb(aic, SCSIRATE, ti->scsirate);
f19fcfb0
PA
834 memset(&neg, 0, sizeof (neg));
835#ifdef CAM_NEW_TRAN_CODE
836 neg.protocol = PROTO_SCSI;
837 neg.protocol_version = SCSI_REV_2;
838 neg.transport = XPORT_SPI;
839 neg.transport_version = 2;
840 spi->sync_period = ti->current.period;
841 spi->sync_offset = ti->current.offset;
842 spi->valid = CTS_SPI_VALID_SYNC_RATE
843 | CTS_SPI_VALID_SYNC_OFFSET;
844#else
984263bc
MD
845 neg.sync_period = ti->current.period;
846 neg.sync_offset = ti->current.offset;
847 neg.valid = CCB_TRANS_SYNC_RATE_VALID
848 | CCB_TRANS_SYNC_OFFSET_VALID;
f19fcfb0 849#endif
984263bc
MD
850 ccb_h = &scb->ccb->ccb_h;
851 xpt_setup_ccb(&neg.ccb_h, ccb_h->path, 1);
852 xpt_async(AC_TRANSFER_NEG, ccb_h->path, &neg);
853 break;
854 default:
855 break;
856 }
857 break;
858 case MSG_SAVEDATAPOINTER:
859 break;
860 case MSG_RESTOREPOINTERS:
861 break;
862 case MSG_NOOP:
863 break;
864 default:
865 aic_sched_msgout(aic, MSG_MESSAGE_REJECT);
866 break;
867 }
868}
869
870/*
871 * Send messages.
872 */
873static void
874aic_msgout(struct aic_softc *aic)
875{
876 struct aic_scb *scb;
877 union ccb *ccb;
878 struct aic_tinfo *ti;
879 int msgidx = 0;
880
881 CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_msgout\n"));
882
883 aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
884 aic_outb(aic, SXFRCTL0, CHEN|SPIOEN);
885
886 /*
887 * If the previous phase is also the message out phase,
888 * we need to retransmit all the messages, probably
889 * because the target has detected a parity error during
890 * the past transmission.
891 */
892 if (aic->prev_phase == PH_MSGOUT)
893 aic->msg_outq = aic->msg_sent;
894
895 do {
896 int q = aic->msg_outq;
897 if (msgidx > 0 && msgidx == aic->msg_len) {
898 /* complete message sent, start the next one */
899 q &= -q;
900 aic->msg_sent |= q;
901 aic->msg_outq ^= q;
902 q = aic->msg_outq;
903 msgidx = 0;
904 }
905 if (msgidx == 0) {
906 /* setup the message */
907 switch (q & -q) {
908 case AIC_MSG_IDENTIFY:
909 scb = aic->nexus;
910 ccb = scb->ccb;
911 ti = &aic->tinfo[scb->target];
912 aic->msg_buf[0] = MSG_IDENTIFY(scb->lun,
913 (ti->flags & TINFO_DISC_ENB) &&
914 !(ccb->ccb_h.flags & CAM_DIS_DISCONNECT));
915 aic->msg_len = 1;
916 break;
917 case AIC_MSG_TAG_Q:
918 scb = aic->nexus;
919 ccb = scb->ccb;
920 aic->msg_buf[0] = ccb->csio.tag_action;
921 aic->msg_buf[1] = scb->tag;
922 aic->msg_len = 2;
923 break;
924 case AIC_MSG_SDTR:
925 scb = aic->nexus;
926 ti = &aic->tinfo[scb->target];
927 aic->msg_buf[0] = MSG_EXTENDED;
928 aic->msg_buf[1] = MSG_EXT_SDTR_LEN;
929 aic->msg_buf[2] = MSG_EXT_SDTR;
930 aic->msg_buf[3] = ti->goal.period;
931 aic->msg_buf[4] = ti->goal.offset;
932 aic->msg_len = MSG_EXT_SDTR_LEN + 2;
933 ti->flags |= TINFO_SDTR_SENT;
934 break;
935 case AIC_MSG_MSGBUF:
936 /* a single message already in the buffer */
937 if (aic->msg_buf[0] == MSG_BUS_DEV_RESET ||
938 aic->msg_buf[0] == MSG_ABORT ||
939 aic->msg_buf[0] == MSG_ABORT_TAG)
940 aic->flags |= AIC_BUSFREE_OK;
941 break;
942 }
943 }
944 /*
945 * If this is the last message byte of all messages,
946 * clear ATNO to signal transmission complete.
947 */
948 if ((q & (q - 1)) == 0 && msgidx == aic->msg_len - 1)
949 aic_outb(aic, CLRSINT1, CLRATNO);
950 /* transmit the message byte */
951 aic_outb(aic, SCSIDAT, aic->msg_buf[msgidx++]);
952 } while (aic_spiordy(aic));
953
954 aic_outb(aic, SXFRCTL0, CHEN);
955 aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
956}
957
958/*
959 * Read data bytes.
960 */
961static void
962aic_datain(struct aic_softc *aic)
963{
964 struct aic_scb *scb = aic->nexus;
965 u_int8_t dmastat, dmacntrl0;
966 int n;
967
968 CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_datain\n"));
969
970 aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
971 aic_outb(aic, SXFRCTL0, SCSIEN|DMAEN|CHEN);
972
973 dmacntrl0 = ENDMA;
974 if (aic->flags & AIC_DWIO_ENABLE)
975 dmacntrl0 |= DWORDPIO;
976 aic_outb(aic, DMACNTRL0, dmacntrl0);
977
978 while (scb->data_len > 0) {
979 for (;;) {
980 /* wait for the fifo to fill up or a phase change */
981 dmastat = aic_inb(aic, DMASTAT);
982 if (dmastat & (INTSTAT|DFIFOFULL))
983 break;
984 }
985 if (dmastat & DFIFOFULL) {
986 n = FIFOSIZE;
987 } else {
988 /*
989 * No more data, wait for the remaining bytes in
990 * the scsi fifo to be transfer to the host fifo.
991 */
992 while (!(aic_inb(aic, SSTAT2) & SEMPTY))
993 ;
994 n = aic_inb(aic, FIFOSTAT);
995 }
996 n = imin(scb->data_len, n);
997 if (aic->flags & AIC_DWIO_ENABLE) {
998 if (n >= 12) {
999 aic_insl(aic, DMADATALONG, scb->data_ptr, n>>2);
1000 scb->data_ptr += n & ~3;
1001 scb->data_len -= n & ~3;
1002 n &= 3;
1003 }
1004 } else {
1005 if (n >= 8) {
1006 aic_insw(aic, DMADATA, scb->data_ptr, n >> 1);
1007 scb->data_ptr += n & ~1;
1008 scb->data_len -= n & ~1;
1009 n &= 1;
1010 }
1011 }
1012 if (n) {
1013 aic_outb(aic, DMACNTRL0, ENDMA|B8MODE);
1014 aic_insb(aic, DMADATA, scb->data_ptr, n);
1015 scb->data_ptr += n;
1016 scb->data_len -= n;
1017 aic_outb(aic, DMACNTRL0, dmacntrl0);
1018 }
1019
1020 if (dmastat & INTSTAT)
1021 break;
1022 }
1023
1024 aic_outb(aic, SXFRCTL0, CHEN);
1025 aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
1026}
1027
1028/*
1029 * Send data bytes.
1030 */
1031static void
1032aic_dataout(struct aic_softc *aic)
1033{
1034 struct aic_scb *scb = aic->nexus;
1035 u_int8_t dmastat, dmacntrl0, sstat2;
1036 int n;
1037
1038 CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_dataout\n"));
1039
1040 aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
1041 aic_outb(aic, SXFRCTL0, SCSIEN|DMAEN|CHEN);
1042
1043 dmacntrl0 = ENDMA|WRITE;
1044 if (aic->flags & AIC_DWIO_ENABLE)
1045 dmacntrl0 |= DWORDPIO;
1046 aic_outb(aic, DMACNTRL0, dmacntrl0);
1047
1048 while (scb->data_len > 0) {
1049 for (;;) {
1050 /* wait for the fifo to clear up or a phase change */
1051 dmastat = aic_inb(aic, DMASTAT);
1052 if (dmastat & (INTSTAT|DFIFOEMP))
1053 break;
1054 }
1055 if (dmastat & INTSTAT)
1056 break;
1057 n = imin(scb->data_len, FIFOSIZE);
1058 if (aic->flags & AIC_DWIO_ENABLE) {
1059 if (n >= 12) {
1060 aic_outsl(aic, DMADATALONG, scb->data_ptr,n>>2);
1061 scb->data_ptr += n & ~3;
1062 scb->data_len -= n & ~3;
1063 n &= 3;
1064 }
1065 } else {
1066 if (n >= 8) {
1067 aic_outsw(aic, DMADATA, scb->data_ptr, n >> 1);
1068 scb->data_ptr += n & ~1;
1069 scb->data_len -= n & ~1;
1070 n &= 1;
1071 }
1072 }
1073 if (n) {
1074 aic_outb(aic, DMACNTRL0, ENDMA|WRITE|B8MODE);
1075 aic_outsb(aic, DMADATA, scb->data_ptr, n);
1076 scb->data_ptr += n;
1077 scb->data_len -= n;
1078 aic_outb(aic, DMACNTRL0, dmacntrl0);
1079 }
1080 }
1081
1082 for (;;) {
1083 /* wait until all bytes in the fifos are transmitted */
1084 dmastat = aic_inb(aic, DMASTAT);
1085 sstat2 = aic_inb(aic, SSTAT2);
1086 if ((dmastat & DFIFOEMP) && (sstat2 & SEMPTY))
1087 break;
1088 if (dmastat & INTSTAT) {
1089 /* adjust for untransmitted bytes */
1090 n = aic_inb(aic, FIFOSTAT) + (sstat2 & 0xf);
1091 scb->data_ptr -= n;
1092 scb->data_len += n;
1093 /* clear the fifo */
1094 aic_outb(aic, SXFRCTL0, CHEN|CLRCH);
1095 aic_outb(aic, DMACNTRL0, RSTFIFO);
1096 break;
1097 }
1098 }
1099
1100 aic_outb(aic, SXFRCTL0, CHEN);
1101 aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
1102}
1103
1104/*
1105 * Send the scsi command.
1106 */
1107static void
1108aic_cmd(struct aic_softc *aic)
1109{
1110 struct aic_scb *scb = aic->nexus;
1111 struct scsi_request_sense sense_cmd;
1112
1113 CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_cmd\n"));
1114
1115 if (scb->flags & SCB_SENSE) {
1116 /* autosense request */
1117 sense_cmd.opcode = REQUEST_SENSE;
1118 sense_cmd.byte2 = scb->lun << 5;
1119 sense_cmd.length = scb->ccb->csio.sense_len;
1120 sense_cmd.control = 0;
1121 sense_cmd.unused[0] = 0;
1122 sense_cmd.unused[1] = 0;
1123 scb->cmd_ptr = (u_int8_t *)&sense_cmd;
1124 scb->cmd_len = sizeof(sense_cmd);
1125 scb->data_ptr = (u_int8_t *)&scb->ccb->csio.sense_data;
1126 scb->data_len = scb->ccb->csio.sense_len;
1127 }
1128
1129 aic_outb(aic, SIMODE1, ENSCSIRST|ENPHASEMIS|ENBUSFREE);
1130 aic_outb(aic, DMACNTRL0, ENDMA|WRITE);
1131 aic_outb(aic, SXFRCTL0, SCSIEN|DMAEN|CHEN);
1132 aic_outsw(aic, DMADATA, (u_int16_t *)scb->cmd_ptr, scb->cmd_len >> 1);
1133 while ((aic_inb(aic, SSTAT2) & SEMPTY) == 0 &&
1134 (aic_inb(aic, DMASTAT) & INTSTAT) == 0)
1135 ;
1136 aic_outb(aic, SXFRCTL0, CHEN);
1137 aic_outb(aic, SIMODE1, ENSCSIRST|ENBUSFREE|ENREQINIT);
1138}
1139
1140/*
1141 * Finish off a command. The caller is responsible to remove the ccb
1142 * from any queue.
1143 */
1144static void
1145aic_done(struct aic_softc *aic, struct aic_scb *scb)
1146{
1147 union ccb *ccb = scb->ccb;
1148
1149 CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE,
1150 ("aic_done - ccb %p status %x resid %d\n",
1151 ccb, ccb->ccb_h.status, ccb->csio.resid));
1152
ddcafce9 1153 callout_stop(&ccb->ccb_h.timeout_ch);
984263bc
MD
1154
1155 if ((scb->flags & SCB_DEVICE_RESET) != 0 &&
1156 ccb->ccb_h.func_code != XPT_RESET_DEV) {
1157 struct cam_path *path;
1158 struct ccb_hdr *ccb_h;
1159 cam_status error;
1160
1161 error = xpt_create_path(&path, /*periph*/NULL,
1162 cam_sim_path(aic->sim),
1163 scb->target,
1164 CAM_LUN_WILDCARD);
1165
1166 if (error == CAM_REQ_CMP) {
1167 xpt_async(AC_SENT_BDR, path, NULL);
1168 xpt_free_path(path);
1169 }
1170
1171 ccb_h = TAILQ_FIRST(&aic->pending_ccbs);
1172 while (ccb_h != NULL) {
1173 struct aic_scb *pending_scb;
1174
1175 pending_scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
1176 if (ccb_h->target_id == scb->target) {
1177 ccb_h->status |= CAM_BDR_SENT;
1178 ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
1179 TAILQ_REMOVE(&aic->pending_ccbs,
1180 &pending_scb->ccb->ccb_h, sim_links.tqe);
1181 aic_done(aic, pending_scb);
1182 } else {
ddcafce9
JS
1183 callout_reset(&ccb_h->timeout_ch,
1184 (ccb_h->timeout * hz) / 1000,
1185 aic_timeout, pending_scb);
984263bc
MD
1186 ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
1187 }
1188 }
1189
1190 ccb_h = TAILQ_FIRST(&aic->nexus_ccbs);
1191 while (ccb_h != NULL) {
1192 struct aic_scb *nexus_scb;
1193
1194 nexus_scb = (struct aic_scb *)ccb_h->ccb_scb_ptr;
1195 if (ccb_h->target_id == scb->target) {
1196 ccb_h->status |= CAM_BDR_SENT;
1197 ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
1198 TAILQ_REMOVE(&aic->nexus_ccbs,
1199 &nexus_scb->ccb->ccb_h, sim_links.tqe);
1200 aic_done(aic, nexus_scb);
1201 } else {
ddcafce9
JS
1202 callout_reset(&ccb_h->timeout_ch,
1203 (ccb_h->timeout * hz) / 1000,
1204 aic_timeout, nexus_scb);
984263bc
MD
1205 ccb_h = TAILQ_NEXT(ccb_h, sim_links.tqe);
1206 }
1207 }
1208 }
1209
1210 if (aic->nexus == scb || scb->flags & SCB_DISCONNECTED)
1211 aic->tinfo[scb->target].lubusy &= ~(1 << scb->lun);
1212
1213 if (aic->nexus == scb) {
1214 aic->nexus = NULL;
1215 }
1216 aic_free_scb(aic, scb);
1217 xpt_done(ccb);
1218}
1219
1220static void
1221aic_poll(struct cam_sim *sim)
1222{
1223 aic_intr(cam_sim_softc(sim));
1224}
1225
1226static void
1227aic_timeout(void *arg)
1228{
1229 struct aic_scb *scb = (struct aic_scb *)arg;
1230 union ccb *ccb = scb->ccb;
1231 struct aic_softc *aic = (struct aic_softc *)ccb->ccb_h.ccb_aic_ptr;
984263bc
MD
1232
1233 xpt_print_path(ccb->ccb_h.path);
e3869ec7 1234 kprintf("ccb %p - timed out", ccb);
984263bc 1235 if (aic->nexus && aic->nexus != scb)
e3869ec7
SW
1236 kprintf(", nexus %p", aic->nexus->ccb);
1237 kprintf(", phase 0x%x, state %d\n", aic_inb(aic, SCSISIGI), aic->state);
984263bc 1238
dee48646 1239 crit_enter();
984263bc
MD
1240
1241 if ((scb->flags & SCB_ACTIVE) == 0) {
dee48646 1242 crit_exit();
984263bc 1243 xpt_print_path(ccb->ccb_h.path);
e3869ec7 1244 kprintf("ccb %p - timed out already completed\n", ccb);
984263bc
MD
1245 return;
1246 }
1247
1248 if ((scb->flags & SCB_DEVICE_RESET) == 0 && aic->nexus == scb) {
1249 struct ccb_hdr *ccb_h = &scb->ccb->ccb_h;
1250
1251 if ((ccb_h->status & CAM_RELEASE_SIMQ) == 0) {
1252 xpt_freeze_simq(aic->sim, /*count*/1);
1253 ccb_h->status |= CAM_RELEASE_SIMQ;
1254 }
1255
ddcafce9
JS
1256 TAILQ_FOREACH(ccb_h, &aic->pending_ccbs, sim_links.tqe)
1257 callout_stop(&ccb_h->timeout_ch);
984263bc 1258
ddcafce9
JS
1259 TAILQ_FOREACH(ccb_h, &aic->nexus_ccbs, sim_links.tqe)
1260 callout_stop(&ccb_h->timeout_ch);
984263bc
MD
1261
1262 scb->flags |= SCB_DEVICE_RESET;
ddcafce9 1263 callout_reset(&ccb->ccb_h.timeout_ch, 5 * hz, aic_timeout, scb);
984263bc
MD
1264 aic_sched_msgout(aic, MSG_BUS_DEV_RESET);
1265 } else {
1266 if (aic->nexus == scb) {
1267 ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
1268 aic_done(aic, scb);
1269 }
1270 aic_reset(aic, /*initiate_reset*/TRUE);
1271 }
1272
dee48646 1273 crit_exit();
984263bc
MD
1274}
1275
1276void
1277aic_intr(void *arg)
1278{
1279 struct aic_softc *aic = (struct aic_softc *)arg;
1280 u_int8_t sstat0, sstat1;
1281 union ccb *ccb;
1282 struct aic_scb *scb;
1283
1284 if (!(aic_inb(aic, DMASTAT) & INTSTAT))
1285 return;
1286
1287 aic_outb(aic, DMACNTRL0, 0);
1288
1289 sstat0 = aic_inb(aic, SSTAT0);
1290 sstat1 = aic_inb(aic, SSTAT1);
1291
1292 if ((sstat1 & SCSIRSTI) != 0) {
1293 /* a device-initiated bus reset */
1294 aic_outb(aic, CLRSINT1, CLRSCSIRSTI);
1295 aic_reset(aic, /*initiate_reset*/FALSE);
1296 return;
1297 }
1298
1299 if ((sstat1 & SCSIPERR) != 0) {
1300 aic_outb(aic, CLRSINT1, CLRSCSIPERR);
1301 aic_sched_msgout(aic, MSG_PARITY_ERROR);
1302 aic_outb(aic, DMACNTRL0, INTEN);
1303 return;
1304 }
1305
1306 if (aic_inb(aic, SSTAT4)) {
1307 aic_outb(aic, CLRSERR, CLRSYNCERR|CLRFWERR|CLRFRERR);
1308 aic_reset(aic, /*initiate_reset*/TRUE);
1309 return;
1310 }
1311
1312 if (aic->state <= AIC_SELECTING) {
1313 if ((sstat0 & SELDI) != 0) {
1314 aic_reselected(aic);
1315 aic_outb(aic, DMACNTRL0, INTEN);
1316 return;
1317 }
1318
1319 if ((sstat0 & SELDO) != 0) {
1320 aic_selected(aic);
1321 aic_outb(aic, DMACNTRL0, INTEN);
1322 return;
1323 }
1324
1325 if ((sstat1 & SELTO) != 0) {
1326 scb = aic->nexus;
1327 ccb = scb->ccb;
1328 ccb->ccb_h.status = CAM_SEL_TIMEOUT;
1329 aic_done(aic, scb);
1330 while ((sstat1 & BUSFREE) == 0)
1331 sstat1 = aic_inb(aic, SSTAT1);
1332 aic->flags |= AIC_BUSFREE_OK;
1333 }
1334 }
1335
1336 if ((sstat1 & BUSFREE) != 0) {
1337 aic_outb(aic, SCSISEQ, 0);
1338 aic_outb(aic, CLRSINT0, sstat0);
1339 aic_outb(aic, CLRSINT1, sstat1);
1340 if ((scb = aic->nexus)) {
1341 if ((aic->flags & AIC_BUSFREE_OK) == 0) {
1342 ccb = scb->ccb;
1343 ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
1344 aic_done(aic, scb);
1345 } else if (scb->flags & SCB_DEVICE_RESET) {
1346 ccb = scb->ccb;
1347 if (ccb->ccb_h.func_code == XPT_RESET_DEV) {
1348 xpt_async(AC_SENT_BDR,
1349 ccb->ccb_h.path, NULL);
1350 ccb->ccb_h.status |= CAM_REQ_CMP;
1351 } else
1352 ccb->ccb_h.status |= CAM_CMD_TIMEOUT;
1353 aic_done(aic, scb);
1354 } else if (scb->flags & SCB_SENSE) {
1355 /* autosense request */
1356 aic->flags &= ~AIC_BUSFREE_OK;
1357 aic->tinfo[scb->target].lubusy &=
1358 ~(1 << scb->lun);
1359 aic_select(aic);
1360 aic_outb(aic, DMACNTRL0, INTEN);
1361 return;
1362 }
1363 }
1364 aic->flags &= ~AIC_BUSFREE_OK;
1365 aic->state = AIC_IDLE;
1366 aic_start(aic);
1367 aic_outb(aic, DMACNTRL0, INTEN);
1368 return;
1369 }
1370
1371 if ((sstat1 & REQINIT) != 0) {
1372 u_int8_t phase = aic_inb(aic, SCSISIGI) & PH_MASK;
1373 aic_outb(aic, SCSISIGO, phase);
1374 aic_outb(aic, CLRSINT1, CLRPHASECHG);
1375
1376 switch (phase) {
1377 case PH_MSGOUT:
1378 aic_msgout(aic);
1379 break;
1380 case PH_MSGIN:
1381 aic_msgin(aic);
1382 break;
1383 case PH_STAT:
1384 scb = aic->nexus;
1385 ccb = scb->ccb;
1386 aic_outb(aic, DMACNTRL0, 0);
1387 aic_outb(aic, SXFRCTL0, CHEN|SPIOEN);
1388 scb->status = aic_inb(aic, SCSIDAT);
1389 aic_outb(aic, SXFRCTL0, CHEN);
1390 break;
1391 case PH_CMD:
1392 aic_cmd(aic);
1393 break;
1394 case PH_DATAIN:
1395 aic_datain(aic);
1396 break;
1397 case PH_DATAOUT:
1398 aic_dataout(aic);
1399 break;
1400 }
1401 aic->prev_phase = phase;
1402 aic_outb(aic, DMACNTRL0, INTEN);
1403 return;
1404 }
1405
e3869ec7 1406 kprintf("aic_intr: unexpected intr sstat0 %x sstat1 %x\n",
984263bc
MD
1407 sstat0, sstat1);
1408 aic_outb(aic, DMACNTRL0, INTEN);
1409}
1410
1411/*
1412 * Reset ourselves.
1413 */
1414static void
1415aic_chip_reset(struct aic_softc *aic)
1416{
1417 /*
1418 * Doc. recommends to clear these two registers before
1419 * operations commence
1420 */
1421 aic_outb(aic, SCSITEST, 0);
1422 aic_outb(aic, TEST, 0);
1423
1424 /* Reset SCSI-FIFO and abort any transfers */
1425 aic_outb(aic, SXFRCTL0, CHEN|CLRCH|CLRSTCNT);
1426
1427 /* Reset HOST-FIFO */
1428 aic_outb(aic, DMACNTRL0, RSTFIFO);
1429 aic_outb(aic, DMACNTRL1, 0);
1430
1431 /* Disable all selection features */
1432 aic_outb(aic, SCSISEQ, 0);
1433 aic_outb(aic, SXFRCTL1, 0);
1434
1435 /* Disable interrupts */
1436 aic_outb(aic, SIMODE0, 0);
1437 aic_outb(aic, SIMODE1, 0);
1438
1439 /* Clear interrupts */
1440 aic_outb(aic, CLRSINT0, 0x7f);
1441 aic_outb(aic, CLRSINT1, 0xef);
1442
1443 /* Disable synchronous transfers */
1444 aic_outb(aic, SCSIRATE, 0);
1445
1446 /* Haven't seen ant errors (yet) */
1447 aic_outb(aic, CLRSERR, 0x07);
1448
1449 /* Set our SCSI-ID */
1450 aic_outb(aic, SCSIID, aic->initiator << OID_S);
1451 aic_outb(aic, BRSTCNTRL, EISA_BRST_TIM);
1452}
1453
1454/*
1455 * Reset the SCSI bus
1456 */
1457static void
1458aic_scsi_reset(struct aic_softc *aic)
1459{
1460 aic_outb(aic, SCSISEQ, SCSIRSTO);
1461 DELAY(500);
1462 aic_outb(aic, SCSISEQ, 0);
1463 DELAY(50);
1464}
1465
1466/*
1467 * Reset. Abort all pending commands.
1468 */
1469static void
1470aic_reset(struct aic_softc *aic, int initiate_reset)
1471{
1472 struct ccb_hdr *ccb_h;
1473
1474 CAM_DEBUG_PRINT(CAM_DEBUG_TRACE, ("aic_reset\n"));
1475
1476 if (initiate_reset)
1477 aic_scsi_reset(aic);
1478 aic_chip_reset(aic);
1479
1480 xpt_async(AC_BUS_RESET, aic->path, NULL);
1481
1482 while ((ccb_h = TAILQ_FIRST(&aic->pending_ccbs)) != NULL) {
1483 TAILQ_REMOVE(&aic->pending_ccbs, ccb_h, sim_links.tqe);
1484 ccb_h->status |= CAM_SCSI_BUS_RESET;
1485 aic_done(aic, (struct aic_scb *)ccb_h->ccb_scb_ptr);
1486 }
1487
1488 while ((ccb_h = TAILQ_FIRST(&aic->nexus_ccbs)) != NULL) {
1489 TAILQ_REMOVE(&aic->nexus_ccbs, ccb_h, sim_links.tqe);
1490 ccb_h->status |= CAM_SCSI_BUS_RESET;
1491 aic_done(aic, (struct aic_scb *)ccb_h->ccb_scb_ptr);
1492 }
1493
1494 if (aic->nexus) {
1495 ccb_h = &aic->nexus->ccb->ccb_h;
1496 ccb_h->status |= CAM_SCSI_BUS_RESET;
1497 aic_done(aic, aic->nexus);
1498 }
1499
1500 aic->state = AIC_IDLE;
1501 aic_outb(aic, DMACNTRL0, INTEN);
1502}
1503
1504static void
1505aic_init(struct aic_softc *aic)
1506{
1507 struct aic_scb *scb;
1508 struct aic_tinfo *ti;
1509 u_int8_t porta, portb;
1510 int i;
1511
1512 TAILQ_INIT(&aic->pending_ccbs);
1513 TAILQ_INIT(&aic->nexus_ccbs);
1514 aic->nexus = NULL;
1515 aic->state = AIC_IDLE;
1516 aic->prev_phase = -1;
1517 aic->flags = 0;
1518
1519 aic_chip_reset(aic);
1520 aic_scsi_reset(aic);
1521
1522 porta = aic_inb(aic, PORTA);
1523 portb = aic_inb(aic, PORTB);
1524
1525 aic->initiator = PORTA_ID(porta);
1526 if (PORTA_PARITY(porta))
1527 aic->flags |= AIC_PARITY_ENABLE;
1528 if (PORTB_DISC(portb))
1529 aic->flags |= AIC_DISC_ENABLE;
1530 if (PORTB_DMA(portb))
1531 aic->flags |= AIC_DMA_ENABLE;
1532 if (aic_inb(aic, REV))
1533 aic->flags |= AIC_DWIO_ENABLE;
1534
1535 free_scbs = NULL;
1536 for (i = 255; i >= 0; i--) {
1537 scb = &aic->scbs[i];
1538 scb->tag = i;
1539 aic_free_scb(aic, scb);
1540 }
1541
1542 for (i = 0; i < 8; i++) {
1543 if (i == aic->initiator)
1544 continue;
1545 ti = &aic->tinfo[i];
1546 bzero(ti, sizeof(*ti));
1547 ti->flags = TINFO_TAG_ENB;
1548 if (aic->flags & AIC_DISC_ENABLE)
1549 ti->flags |= TINFO_DISC_ENB;
1550 ti->user.period = AIC_SYNC_PERIOD;
1551 ti->user.offset = AIC_SYNC_OFFSET;
1552 ti->scsirate = 0;
1553 }
1554
1555 aic_outb(aic, DMACNTRL0, INTEN);
1556}
1557
1558int
1559aic_probe(struct aic_softc *aic)
1560{
1561 int i;
1562
1563 /* Remove aic6360 from possible powerdown mode */
1564 aic_outb(aic, DMACNTRL0, 0);
1565
1566#define STSIZE 16
1567 aic_outb(aic, DMACNTRL1, 0); /* Reset stack pointer */
1568 for (i = 0; i < STSIZE; i++)
1569 aic_outb(aic, STACK, i);
1570
1571 /* See if we can pull out the same sequence */
1572 aic_outb(aic, DMACNTRL1, 0);
1573 for (i = 0; i < STSIZE && aic_inb(aic, STACK) == i; i++)
1574 ;
1575 if (i != STSIZE)
1576 return (ENXIO);
1577#undef STSIZE
1578 return (0);
1579}
1580
1581int
1582aic_attach(struct aic_softc *aic)
1583{
984263bc
MD
1584 /*
1585 * Construct our SIM entry
1586 */
1587 aic->sim = cam_sim_alloc(aic_action, aic_poll, "aic", aic,
3aed1355
MD
1588 aic->unit, 2, 256, NULL);
1589 if (aic->sim == NULL)
984263bc 1590 return (ENOMEM);
984263bc
MD
1591
1592 if (xpt_bus_register(aic->sim, 0) != CAM_SUCCESS) {
3aed1355 1593 cam_sim_free(aic->sim);
984263bc
MD
1594 return (ENXIO);
1595 }
1596
1597 if (xpt_create_path(&aic->path, /*periph*/NULL,
1598 cam_sim_path(aic->sim), CAM_TARGET_WILDCARD,
1599 CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
1600 xpt_bus_deregister(cam_sim_path(aic->sim));
3aed1355 1601 cam_sim_free(aic->sim);
984263bc
MD
1602 return (ENXIO);
1603 }
1604
1605 aic_init(aic);
1606
e3869ec7 1607 kprintf("aic%d: %s", aic->unit,
984263bc
MD
1608 aic_inb(aic, REV) > 0 ? "aic6360" : "aic6260");
1609 if (aic->flags & AIC_DMA_ENABLE)
e3869ec7 1610 kprintf(", dma");
984263bc 1611 if (aic->flags & AIC_DISC_ENABLE)
e3869ec7 1612 kprintf(", disconnection");
984263bc 1613 if (aic->flags & AIC_PARITY_ENABLE)
e3869ec7
SW
1614 kprintf(", parity check");
1615 kprintf("\n");
984263bc
MD
1616 return (0);
1617}
1618
1619int
1620aic_detach(struct aic_softc *aic)
1621{
1622 xpt_async(AC_LOST_DEVICE, aic->path, NULL);
1623 xpt_free_path(aic->path);
1624 xpt_bus_deregister(cam_sim_path(aic->sim));
3aed1355 1625 cam_sim_free(aic->sim);
984263bc
MD
1626 return (0);
1627}