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