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