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