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