[BACK]Return to isp_target.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/isp_target.c, Revision 1.1

1.1     ! nbrk        1: /* $OpenBSD: isp_target.c,v 1.14 2007/02/14 00:53:48 jsg Exp $ */
        !             2: /*
        !             3:  * Machine and OS Independent Target Mode Code for the Qlogic SCSI/FC adapters.
        !             4:  *
        !             5:  * Copyright (c) 1999, 2000, 2001 by Matthew Jacob
        !             6:  * All rights reserved.
        !             7:  * mjacob@feral.com
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice immediately at the beginning of the file, without modification,
        !            14:  *    this list of conditions, and the following disclaimer.
        !            15:  * 2. The name of the author may not be used to endorse or promote products
        !            16:  *    derived from this software without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            21:  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
        !            22:  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            28:  * SUCH DAMAGE.
        !            29:  */
        !            30:
        !            31: /*
        !            32:  * Bug fixes gratefully acknowledged from:
        !            33:  *     Oded Kedem <oded@kashya.com>
        !            34:  */
        !            35: /*
        !            36:  * Include header file appropriate for platform we're building on.
        !            37:  */
        !            38:
        !            39: #ifdef __NetBSD__
        !            40: #include <dev/ic/isp_netbsd.h>
        !            41: #endif
        !            42: #ifdef __FreeBSD__
        !            43: #include <dev/isp/isp_freebsd.h>
        !            44: #endif
        !            45: #ifdef __OpenBSD__
        !            46: #include <dev/ic/isp_openbsd.h>
        !            47: #endif
        !            48: #ifdef __linux__
        !            49: #include "isp_linux.h"
        !            50: #endif
        !            51:
        !            52: #ifdef ISP_TARGET_MODE
        !            53: static const char atiocope[] =
        !            54:     "ATIO returned for lun %d because it was in the middle of Bus Device Reset "
        !            55:     "on bus %d";
        !            56: static const char atior[] =
        !            57:     "ATIO returned on for lun %d on from IID %d because a Bus Reset occurred "
        !            58:     "on bus %d";
        !            59:
        !            60: static void isp_got_msg(struct ispsoftc *, int, in_entry_t *);
        !            61: static void isp_got_msg_fc(struct ispsoftc *, int, in_fcentry_t *);
        !            62: static void isp_notify_ack(struct ispsoftc *, void *);
        !            63: static void isp_handle_atio(struct ispsoftc *, at_entry_t *);
        !            64: static void isp_handle_atio2(struct ispsoftc *, at2_entry_t *);
        !            65: static void isp_handle_ctio(struct ispsoftc *, ct_entry_t *);
        !            66: static void isp_handle_ctio2(struct ispsoftc *, ct2_entry_t *);
        !            67:
        !            68: /*
        !            69:  * The Qlogic driver gets an interrupt to look at response queue entries.
        !            70:  * Some of these are status completions for initiatior mode commands, but
        !            71:  * if target mode is enabled, we get a whole wad of response queue entries
        !            72:  * to be handled here.
        !            73:  *
        !            74:  * Basically the split into 3 main groups: Lun Enable/Modification responses,
        !            75:  * SCSI Command processing, and Immediate Notification events.
        !            76:  *
        !            77:  * You start by writing a request queue entry to enable target mode (and
        !            78:  * establish some resource limitations which you can modify later).
        !            79:  * The f/w responds with a LUN ENABLE or LUN MODIFY response with
        !            80:  * the status of this action. If the enable was successful, you can expect...
        !            81:  *
        !            82:  * Response queue entries with SCSI commands encapsulate show up in an ATIO
        !            83:  * (Accept Target IO) type- sometimes with enough info to stop the command at
        !            84:  * this level. Ultimately the driver has to feed back to the f/w's request
        !            85:  * queue a sequence of CTIOs (continue target I/O) that describe data to
        !            86:  * be moved and/or status to be sent) and finally finishing with sending
        !            87:  * to the f/w's response queue an ATIO which then completes the handshake
        !            88:  * with the f/w for that command. There's a lot of variations on this theme,
        !            89:  * including flags you can set in the CTIO for the Qlogic 2X00 fibre channel
        !            90:  * cards that 'auto-replenish' the f/w's ATIO count, but this is the basic
        !            91:  * gist of it.
        !            92:  *
        !            93:  * The third group that can show up in the response queue are Immediate
        !            94:  * Notification events. These include things like notifications of SCSI bus
        !            95:  * resets, or Bus Device Reset messages or other messages received. This
        !            96:  * a classic oddbins area. It can get  a little weird because you then turn
        !            97:  * around and acknowledge the Immediate Notify by writing an entry onto the
        !            98:  * request queue and then the f/w turns around and gives you an acknowledgement
        !            99:  * to *your* acknowledgement on the response queue (the idea being to let
        !           100:  * the f/w tell you when the event is *really* over I guess).
        !           101:  *
        !           102:  */
        !           103:
        !           104:
        !           105: /*
        !           106:  * A new response queue entry has arrived. The interrupt service code
        !           107:  * has already swizzled it into the platform dependent from canonical form.
        !           108:  *
        !           109:  * Because of the way this driver is designed, unfortunately most of the
        !           110:  * actual synchronization work has to be done in the platform-specific
        !           111:  * code - we have no synchronization primitives in the common code.
        !           112:  */
        !           113:
        !           114: int
        !           115: isp_target_notify(struct ispsoftc *isp, void *vptr, u_int16_t *optrp)
        !           116: {
        !           117:        u_int16_t status, seqid;
        !           118:        union {
        !           119:                at_entry_t      *atiop;
        !           120:                at2_entry_t     *at2iop;
        !           121:                ct_entry_t      *ctiop;
        !           122:                ct2_entry_t     *ct2iop;
        !           123:                lun_entry_t     *lunenp;
        !           124:                in_entry_t      *inotp;
        !           125:                in_fcentry_t    *inot_fcp;
        !           126:                na_entry_t      *nackp;
        !           127:                na_fcentry_t    *nack_fcp;
        !           128:                isphdr_t        *hp;
        !           129:                void *          *vp;
        !           130: #define        atiop           unp.atiop
        !           131: #define        at2iop          unp.at2iop
        !           132: #define        ctiop           unp.ctiop
        !           133: #define        ct2iop          unp.ct2iop
        !           134: #define        lunenp          unp.lunenp
        !           135: #define        inotp           unp.inotp
        !           136: #define        inot_fcp        unp.inot_fcp
        !           137: #define        nackp           unp.nackp
        !           138: #define        nack_fcp        unp.nack_fcp
        !           139: #define        hdrp            unp.hp
        !           140:        } unp;
        !           141:        u_int8_t local[QENTRY_LEN];
        !           142:        int bus, type, rval = 1;
        !           143:
        !           144:        type = isp_get_response_type(isp, (isphdr_t *)vptr);
        !           145:        unp.vp = vptr;
        !           146:
        !           147:        ISP_TDQE(isp, "isp_target_notify", (int) *optrp, vptr);
        !           148:
        !           149:        switch(type) {
        !           150:        case RQSTYPE_ATIO:
        !           151:                isp_get_atio(isp, atiop, (at_entry_t *) local);
        !           152:                isp_handle_atio(isp, (at_entry_t *) local);
        !           153:                break;
        !           154:        case RQSTYPE_CTIO:
        !           155:                isp_get_ctio(isp, ctiop, (ct_entry_t *) local);
        !           156:                isp_handle_ctio(isp, (ct_entry_t *) local);
        !           157:                break;
        !           158:        case RQSTYPE_ATIO2:
        !           159:                isp_get_atio2(isp, at2iop, (at2_entry_t *) local);
        !           160:                isp_handle_atio2(isp, (at2_entry_t *) local);
        !           161:                break;
        !           162:        case RQSTYPE_CTIO2:
        !           163:                isp_get_ctio2(isp, ct2iop, (ct2_entry_t *) local);
        !           164:                isp_handle_ctio2(isp, (ct2_entry_t *) local);
        !           165:                break;
        !           166:        case RQSTYPE_ENABLE_LUN:
        !           167:        case RQSTYPE_MODIFY_LUN:
        !           168:                isp_get_enable_lun(isp, lunenp, (lun_entry_t *) local);
        !           169:                (void) isp_async(isp, ISPASYNC_TARGET_ACTION, local);
        !           170:                break;
        !           171:
        !           172:        case RQSTYPE_NOTIFY:
        !           173:                /*
        !           174:                 * Either the ISP received a SCSI message it can't
        !           175:                 * handle, or it's returning an Immed. Notify entry
        !           176:                 * we sent. We can send Immed. Notify entries to
        !           177:                 * increment the firmware's resource count for them
        !           178:                 * (we set this initially in the Enable Lun entry).
        !           179:                 */
        !           180:                bus = 0;
        !           181:                if (IS_FC(isp)) {
        !           182:                        isp_get_notify_fc(isp, inot_fcp, (in_fcentry_t *)local);
        !           183:                        inot_fcp = (in_fcentry_t *) local;
        !           184:                        status = inot_fcp->in_status;
        !           185:                        seqid = inot_fcp->in_seqid;
        !           186:                } else {
        !           187:                        isp_get_notify(isp, inotp, (in_entry_t *)local);
        !           188:                        inotp = (in_entry_t *) local;
        !           189:                        status = inotp->in_status & 0xff;
        !           190:                        seqid = inotp->in_seqid;
        !           191:                        if (IS_DUALBUS(isp)) {
        !           192:                                bus = GET_BUS_VAL(inotp->in_iid);
        !           193:                                SET_BUS_VAL(inotp->in_iid, 0);
        !           194:                        }
        !           195:                }
        !           196:                isp_prt(isp, ISP_LOGTDEBUG0,
        !           197:                    "Immediate Notify On Bus %d, status=0x%x seqid=0x%x",
        !           198:                    bus, status, seqid);
        !           199:
        !           200:                /*
        !           201:                 * ACK it right away.
        !           202:                 */
        !           203:                isp_notify_ack(isp, (status == IN_RESET)? NULL : local);
        !           204:                switch (status) {
        !           205:                case IN_RESET:
        !           206:                        (void) isp_async(isp, ISPASYNC_BUS_RESET, &bus);
        !           207:                        break;
        !           208:                case IN_MSG_RECEIVED:
        !           209:                case IN_IDE_RECEIVED:
        !           210:                        if (IS_FC(isp)) {
        !           211:                                isp_got_msg_fc(isp, bus, (in_fcentry_t *)local);
        !           212:                        } else {
        !           213:                                isp_got_msg(isp, bus, (in_entry_t *)local);
        !           214:                        }
        !           215:                        break;
        !           216:                case IN_RSRC_UNAVAIL:
        !           217:                        isp_prt(isp, ISP_LOGWARN, "Firmware out of ATIOs");
        !           218:                        break;
        !           219:                case IN_PORT_LOGOUT:
        !           220:                case IN_ABORT_TASK:
        !           221:                case IN_PORT_CHANGED:
        !           222:                case IN_GLOBAL_LOGO:
        !           223:                        (void) isp_async(isp, ISPASYNC_TARGET_ACTION, &local);
        !           224:                        break;
        !           225:                default:
        !           226:                        isp_prt(isp, ISP_LOGERR,
        !           227:                            "bad status (0x%x) in isp_target_notify", status);
        !           228:                        break;
        !           229:                }
        !           230:                break;
        !           231:
        !           232:        case RQSTYPE_NOTIFY_ACK:
        !           233:                /*
        !           234:                 * The ISP is acknowledging our acknowledgement of an
        !           235:                 * Immediate Notify entry for some asynchronous event.
        !           236:                 */
        !           237:                if (IS_FC(isp)) {
        !           238:                        isp_get_notify_ack_fc(isp, nack_fcp,
        !           239:                            (na_fcentry_t *)local);
        !           240:                        nack_fcp = (na_fcentry_t *)local;
        !           241:                        isp_prt(isp, ISP_LOGTDEBUG1,
        !           242:                            "Notify Ack status=0x%x seqid 0x%x",
        !           243:                            nack_fcp->na_status, nack_fcp->na_seqid);
        !           244:                } else {
        !           245:                        isp_get_notify_ack(isp, nackp, (na_entry_t *)local);
        !           246:                        nackp = (na_entry_t *)local;
        !           247:                        isp_prt(isp, ISP_LOGTDEBUG1,
        !           248:                            "Notify Ack event 0x%x status=0x%x seqid 0x%x",
        !           249:                            nackp->na_event, nackp->na_status, nackp->na_seqid);
        !           250:                }
        !           251:                break;
        !           252:        default:
        !           253:                isp_prt(isp, ISP_LOGERR,
        !           254:                    "Unknown entry type 0x%x in isp_target_notify", type);
        !           255:                rval = 0;
        !           256:                break;
        !           257:        }
        !           258: #undef atiop
        !           259: #undef at2iop
        !           260: #undef ctiop
        !           261: #undef ct2iop
        !           262: #undef lunenp
        !           263: #undef inotp
        !           264: #undef inot_fcp
        !           265: #undef nackp
        !           266: #undef nack_fcp
        !           267: #undef hdrp
        !           268:        return (rval);
        !           269: }
        !           270:
        !           271:
        !           272: /*
        !           273:  * Toggle (on/off) target mode for bus/target/lun
        !           274:  *
        !           275:  * The caller has checked for overlap and legality.
        !           276:  *
        !           277:  * Note that not all of bus, target or lun can be paid attention to.
        !           278:  * Note also that this action will not be complete until the f/w writes
        !           279:  * response entry. The caller is responsible for synchronizing this.
        !           280:  */
        !           281: int
        !           282: isp_lun_cmd(struct ispsoftc *isp, int cmd, int bus, int tgt, int lun,
        !           283:     int cmd_cnt, int inot_cnt, u_int32_t opaque)
        !           284: {
        !           285:        lun_entry_t el;
        !           286:        u_int16_t nxti, optr;
        !           287:        void *outp;
        !           288:
        !           289:
        !           290:        MEMZERO(&el, sizeof (el));
        !           291:        if (IS_DUALBUS(isp)) {
        !           292:                el.le_rsvd = (bus & 0x1) << 7;
        !           293:        }
        !           294:        el.le_cmd_count = cmd_cnt;
        !           295:        el.le_in_count = inot_cnt;
        !           296:        if (cmd == RQSTYPE_ENABLE_LUN) {
        !           297:                if (IS_SCSI(isp)) {
        !           298:                        el.le_flags = LUN_TQAE|LUN_DISAD;
        !           299:                        el.le_cdb6len = 12;
        !           300:                        el.le_cdb7len = 12;
        !           301:                }
        !           302:        } else if (cmd == -RQSTYPE_ENABLE_LUN) {
        !           303:                cmd = RQSTYPE_ENABLE_LUN;
        !           304:                el.le_cmd_count = 0;
        !           305:                el.le_in_count = 0;
        !           306:        } else if (cmd == -RQSTYPE_MODIFY_LUN) {
        !           307:                cmd = RQSTYPE_MODIFY_LUN;
        !           308:                el.le_ops = LUN_CCDECR | LUN_INDECR;
        !           309:        } else {
        !           310:                el.le_ops = LUN_CCINCR | LUN_ININCR;
        !           311:        }
        !           312:        el.le_header.rqs_entry_type = cmd;
        !           313:        el.le_header.rqs_entry_count = 1;
        !           314:        el.le_reserved = opaque;
        !           315:        if (IS_SCSI(isp)) {
        !           316:                el.le_tgt = tgt;
        !           317:                el.le_lun = lun;
        !           318:        } else if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) {
        !           319:                el.le_lun = lun;
        !           320:        }
        !           321:        el.le_timeout = 2;
        !           322:
        !           323:        if (isp_getrqentry(isp, &nxti, &optr, &outp)) {
        !           324:                isp_prt(isp, ISP_LOGERR,
        !           325:                    "Request Queue Overflow in isp_lun_cmd");
        !           326:                return (-1);
        !           327:        }
        !           328:        ISP_TDQE(isp, "isp_lun_cmd", (int) optr, &el);
        !           329:        isp_put_enable_lun(isp, &el, outp);
        !           330:        ISP_ADD_REQUEST(isp, nxti);
        !           331:        return (0);
        !           332: }
        !           333:
        !           334:
        !           335: int
        !           336: isp_target_put_entry(struct ispsoftc *isp, void *ap)
        !           337: {
        !           338:        void *outp;
        !           339:        u_int16_t nxti, optr;
        !           340:        u_int8_t etype = ((isphdr_t *) ap)->rqs_entry_type;
        !           341:
        !           342:        if (isp_getrqentry(isp, &nxti, &optr, &outp)) {
        !           343:                isp_prt(isp, ISP_LOGWARN,
        !           344:                    "Request Queue Overflow in isp_target_put_entry");
        !           345:                return (-1);
        !           346:        }
        !           347:        switch (etype) {
        !           348:        case RQSTYPE_ATIO:
        !           349:                isp_put_atio(isp, (at_entry_t *) ap, (at_entry_t *) outp);
        !           350:                break;
        !           351:        case RQSTYPE_ATIO2:
        !           352:                isp_put_atio2(isp, (at2_entry_t *) ap, (at2_entry_t *) outp);
        !           353:                break;
        !           354:        case RQSTYPE_CTIO:
        !           355:                isp_put_ctio(isp, (ct_entry_t *) ap, (ct_entry_t *) outp);
        !           356:                break;
        !           357:        case RQSTYPE_CTIO2:
        !           358:                isp_put_ctio2(isp, (ct2_entry_t *) ap, (ct2_entry_t *) outp);
        !           359:                break;
        !           360:        default:
        !           361:                isp_prt(isp, ISP_LOGERR,
        !           362:                    "Unknown type 0x%x in isp_put_entry", etype);
        !           363:                return (-1);
        !           364:        }
        !           365:
        !           366:        ISP_TDQE(isp, "isp_target_put_entry", (int) optr, ap);
        !           367:        ISP_ADD_REQUEST(isp, nxti);
        !           368:        return (0);
        !           369: }
        !           370:
        !           371: int
        !           372: isp_target_put_atio(struct ispsoftc *isp, void *arg)
        !           373: {
        !           374:        union {
        !           375:                at_entry_t _atio;
        !           376:                at2_entry_t _atio2;
        !           377:        } atun;
        !           378:
        !           379:        MEMZERO(&atun, sizeof atun);
        !           380:        if (IS_FC(isp)) {
        !           381:                at2_entry_t *aep = arg;
        !           382:                atun._atio2.at_header.rqs_entry_type = RQSTYPE_ATIO2;
        !           383:                atun._atio2.at_header.rqs_entry_count = 1;
        !           384:                if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {
        !           385:                        atun._atio2.at_scclun = (u_int16_t) aep->at_scclun;
        !           386:                } else {
        !           387:                        atun._atio2.at_lun = (u_int8_t) aep->at_lun;
        !           388:                }
        !           389:                atun._atio2.at_iid = aep->at_iid;
        !           390:                atun._atio2.at_rxid = aep->at_rxid;
        !           391:                atun._atio2.at_status = CT_OK;
        !           392:        } else {
        !           393:                at_entry_t *aep = arg;
        !           394:                atun._atio.at_header.rqs_entry_type = RQSTYPE_ATIO;
        !           395:                atun._atio.at_header.rqs_entry_count = 1;
        !           396:                atun._atio.at_handle = aep->at_handle;
        !           397:                atun._atio.at_iid = aep->at_iid;
        !           398:                atun._atio.at_tgt = aep->at_tgt;
        !           399:                atun._atio.at_lun = aep->at_lun;
        !           400:                atun._atio.at_tag_type = aep->at_tag_type;
        !           401:                atun._atio.at_tag_val = aep->at_tag_val;
        !           402:                atun._atio.at_status = (aep->at_flags & AT_TQAE);
        !           403:                atun._atio.at_status |= CT_OK;
        !           404:        }
        !           405:        return (isp_target_put_entry(isp, &atun));
        !           406: }
        !           407:
        !           408: /*
        !           409:  * Command completion- both for handling cases of no resources or
        !           410:  * no blackhole driver, or other cases where we have to, inline,
        !           411:  * finish the command sanely, or for normal command completion.
        !           412:  *
        !           413:  * The 'completion' code value has the scsi status byte in the low 8 bits.
        !           414:  * If status is a CHECK CONDITION and bit 8 is nonzero, then bits 12..15 have
        !           415:  * the sense key and  bits 16..23 have the ASCQ and bits 24..31 have the ASC
        !           416:  * values.
        !           417:  *
        !           418:  * NB: the key, asc, ascq, cannot be used for parallel SCSI as it doesn't
        !           419:  * NB: inline SCSI sense reporting. As such, we lose this information. XXX.
        !           420:  *
        !           421:  * For both parallel && fibre channel, we use the feature that does
        !           422:  * an automatic resource autoreplenish so we don't have then later do
        !           423:  * put of an atio to replenish the f/w's resource count.
        !           424:  */
        !           425:
        !           426: int
        !           427: isp_endcmd(struct ispsoftc *isp, void *arg, u_int32_t code, u_int16_t hdl)
        !           428: {
        !           429:        int sts;
        !           430:        union {
        !           431:                ct_entry_t _ctio;
        !           432:                ct2_entry_t _ctio2;
        !           433:        } un;
        !           434:
        !           435:        MEMZERO(&un, sizeof un);
        !           436:        sts = code & 0xff;
        !           437:
        !           438:        if (IS_FC(isp)) {
        !           439:                at2_entry_t *aep = arg;
        !           440:                ct2_entry_t *cto = &un._ctio2;
        !           441:
        !           442:                cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
        !           443:                cto->ct_header.rqs_entry_count = 1;
        !           444:                cto->ct_iid = aep->at_iid;
        !           445:                if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) {
        !           446:                        cto->ct_lun = aep->at_lun;
        !           447:                }
        !           448:                cto->ct_rxid = aep->at_rxid;
        !           449:                cto->rsp.m1.ct_scsi_status = sts & 0xff;
        !           450:                cto->ct_flags = CT2_SENDSTATUS | CT2_NO_DATA | CT2_FLAG_MODE1;
        !           451:                if (hdl == 0) {
        !           452:                        cto->ct_flags |= CT2_CCINCR;
        !           453:                }
        !           454:                if (aep->at_datalen) {
        !           455:                        cto->ct_resid = aep->at_datalen;
        !           456:                        cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER;
        !           457:                }
        !           458:                if ((sts & 0xff) == SCSI_CHECK && (sts & ECMD_SVALID)) {
        !           459:                        cto->rsp.m1.ct_resp[0] = 0xf0;
        !           460:                        cto->rsp.m1.ct_resp[2] = (code >> 12) & 0xf;
        !           461:                        cto->rsp.m1.ct_resp[7] = 8;
        !           462:                        cto->rsp.m1.ct_resp[12] = (code >> 24) & 0xff;
        !           463:                        cto->rsp.m1.ct_resp[13] = (code >> 16) & 0xff;
        !           464:                        cto->rsp.m1.ct_senselen = 16;
        !           465:                        cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID;
        !           466:                }
        !           467:                cto->ct_syshandle = hdl;
        !           468:        } else {
        !           469:                at_entry_t *aep = arg;
        !           470:                ct_entry_t *cto = &un._ctio;
        !           471:
        !           472:                cto->ct_header.rqs_entry_type = RQSTYPE_CTIO;
        !           473:                cto->ct_header.rqs_entry_count = 1;
        !           474:                cto->ct_fwhandle = aep->at_handle;
        !           475:                cto->ct_iid = aep->at_iid;
        !           476:                cto->ct_tgt = aep->at_tgt;
        !           477:                cto->ct_lun = aep->at_lun;
        !           478:                cto->ct_tag_type = aep->at_tag_type;
        !           479:                cto->ct_tag_val = aep->at_tag_val;
        !           480:                if (aep->at_flags & AT_TQAE) {
        !           481:                        cto->ct_flags |= CT_TQAE;
        !           482:                }
        !           483:                cto->ct_flags = CT_SENDSTATUS | CT_NO_DATA;
        !           484:                if (hdl == 0) {
        !           485:                        cto->ct_flags |= CT_CCINCR;
        !           486:                }
        !           487:                cto->ct_scsi_status = sts;
        !           488:                cto->ct_syshandle = hdl;
        !           489:        }
        !           490:        return (isp_target_put_entry(isp, &un));
        !           491: }
        !           492:
        !           493: int
        !           494: isp_target_async(struct ispsoftc *isp, int bus, int event)
        !           495: {
        !           496:        tmd_event_t evt;
        !           497:        tmd_msg_t msg;
        !           498:
        !           499:        switch (event) {
        !           500:        /*
        !           501:         * These three we handle here to propagate an effective bus reset
        !           502:         * upstream, but these do not require any immediate notify actions
        !           503:         * so we return when done.
        !           504:         */
        !           505:        case ASYNC_LIP_F8:
        !           506:        case ASYNC_LIP_OCCURRED:
        !           507:        case ASYNC_LOOP_UP:
        !           508:        case ASYNC_LOOP_DOWN:
        !           509:        case ASYNC_LOOP_RESET:
        !           510:        case ASYNC_PTPMODE:
        !           511:                /*
        !           512:                 * These don't require any immediate notify actions. We used
        !           513:                 * treat them like SCSI Bus Resets, but that was just plain
        !           514:                 * wrong. Let the normal CTIO completion report what occurred.
        !           515:                 */
        !           516:                 return (0);
        !           517:
        !           518:        case ASYNC_BUS_RESET:
        !           519:        case ASYNC_TIMEOUT_RESET:
        !           520:                if (IS_FC(isp)) {
        !           521:                        return (0); /* we'll be getting an inotify instead */
        !           522:                }
        !           523:                evt.ev_bus = bus;
        !           524:                evt.ev_event = event;
        !           525:                (void) isp_async(isp, ISPASYNC_TARGET_EVENT, &evt);
        !           526:                break;
        !           527:        case ASYNC_DEVICE_RESET:
        !           528:                /*
        !           529:                 * Bus Device Reset resets a specific target, so
        !           530:                 * we pass this as a synthesized message.
        !           531:                 */
        !           532:                MEMZERO(&msg, sizeof msg);
        !           533:                if (IS_FC(isp)) {
        !           534:                        msg.nt_iid = FCPARAM(isp)->isp_loopid;
        !           535:                } else {
        !           536:                        msg.nt_iid = SDPARAM(isp)->isp_initiator_id;
        !           537:                }
        !           538:                msg.nt_bus = bus;
        !           539:                msg.nt_msg[0] = MSG_BUS_DEV_RESET;
        !           540:                (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg);
        !           541:                break;
        !           542:        default:
        !           543:                isp_prt(isp, ISP_LOGERR,
        !           544:                    "isp_target_async: unknown event 0x%x", event);
        !           545:                break;
        !           546:        }
        !           547:        if (isp->isp_state == ISP_RUNSTATE)
        !           548:                isp_notify_ack(isp, NULL);
        !           549:        return(0);
        !           550: }
        !           551:
        !           552:
        !           553: /*
        !           554:  * Process a received message.
        !           555:  * The ISP firmware can handle most messages, there are only
        !           556:  * a few that we need to deal with:
        !           557:  * - abort: clean up the current command
        !           558:  * - abort tag and clear queue
        !           559:  */
        !           560:
        !           561: static void
        !           562: isp_got_msg(struct ispsoftc *isp, int bus, in_entry_t *inp)
        !           563: {
        !           564:        u_int8_t status = inp->in_status & ~QLTM_SVALID;
        !           565:
        !           566:        if (status == IN_IDE_RECEIVED || status == IN_MSG_RECEIVED) {
        !           567:                tmd_msg_t msg;
        !           568:
        !           569:                MEMZERO(&msg, sizeof (msg));
        !           570:                msg.nt_bus = bus;
        !           571:                msg.nt_iid = inp->in_iid;
        !           572:                msg.nt_tgt = inp->in_tgt;
        !           573:                msg.nt_lun = inp->in_lun;
        !           574:                msg.nt_tagtype = inp->in_tag_type;
        !           575:                msg.nt_tagval = inp->in_tag_val;
        !           576:                MEMCPY(msg.nt_msg, inp->in_msg, IN_MSGLEN);
        !           577:                (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg);
        !           578:        } else {
        !           579:                isp_prt(isp, ISP_LOGERR,
        !           580:                    "unknown immediate notify status 0x%x", inp->in_status);
        !           581:        }
        !           582: }
        !           583:
        !           584: /*
        !           585:  * Synthesize a message from the task management flags in a FCP_CMND_IU.
        !           586:  */
        !           587: static void
        !           588: isp_got_msg_fc(struct ispsoftc *isp, int bus, in_fcentry_t *inp)
        !           589: {
        !           590:        int lun;
        !           591:        static const char f1[] = "%s from iid %d lun %d seq 0x%x";
        !           592:        static const char f2[] =
        !           593:            "unknown %s 0x%x lun %d iid %d task flags 0x%x seq 0x%x\n";
        !           594:
        !           595:        if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {
        !           596:                lun = inp->in_scclun;
        !           597:        } else {
        !           598:                lun = inp->in_lun;
        !           599:        }
        !           600:
        !           601:        if (inp->in_status != IN_MSG_RECEIVED) {
        !           602:                isp_prt(isp, ISP_LOGINFO, f2, "immediate notify status",
        !           603:                    inp->in_status, lun, inp->in_iid,
        !           604:                    inp->in_task_flags,  inp->in_seqid);
        !           605:        } else {
        !           606:                tmd_msg_t msg;
        !           607:
        !           608:                MEMZERO(&msg, sizeof (msg));
        !           609:                msg.nt_bus = bus;
        !           610:                msg.nt_iid = inp->in_iid;
        !           611:                msg.nt_tagval = inp->in_seqid;
        !           612:                msg.nt_lun = lun;
        !           613:
        !           614:                if (inp->in_task_flags & TASK_FLAGS_ABORT_TASK) {
        !           615:                        isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK",
        !           616:                            inp->in_iid, lun, inp->in_seqid);
        !           617:                        msg.nt_msg[0] = MSG_ABORT_TAG;
        !           618:                } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_TASK_SET) {
        !           619:                        isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET",
        !           620:                            inp->in_iid, lun, inp->in_seqid);
        !           621:                        msg.nt_msg[0] = MSG_CLEAR_QUEUE;
        !           622:                } else if (inp->in_task_flags & TASK_FLAGS_TARGET_RESET) {
        !           623:                        isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET",
        !           624:                            inp->in_iid, lun, inp->in_seqid);
        !           625:                        msg.nt_msg[0] = MSG_BUS_DEV_RESET;
        !           626:                } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_ACA) {
        !           627:                        isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA",
        !           628:                            inp->in_iid, lun, inp->in_seqid);
        !           629:                        /* ???? */
        !           630:                        msg.nt_msg[0] = MSG_REL_RECOVERY;
        !           631:                } else if (inp->in_task_flags & TASK_FLAGS_TERMINATE_TASK) {
        !           632:                        isp_prt(isp, ISP_LOGINFO, f1, "TERMINATE TASK",
        !           633:                            inp->in_iid, lun, inp->in_seqid);
        !           634:                        msg.nt_msg[0] = MSG_TERM_IO_PROC;
        !           635:                } else {
        !           636:                        isp_prt(isp, ISP_LOGWARN, f2, "task flag",
        !           637:                            inp->in_status, lun, inp->in_iid,
        !           638:                            inp->in_task_flags,  inp->in_seqid);
        !           639:                }
        !           640:                if (msg.nt_msg[0]) {
        !           641:                        (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg);
        !           642:                }
        !           643:        }
        !           644: }
        !           645:
        !           646: static void
        !           647: isp_notify_ack(struct ispsoftc *isp, void *arg)
        !           648: {
        !           649:        char storage[QENTRY_LEN];
        !           650:        u_int16_t nxti, optr;
        !           651:        void *outp;
        !           652:
        !           653:        if (isp_getrqentry(isp, &nxti, &optr, &outp)) {
        !           654:                isp_prt(isp, ISP_LOGWARN,
        !           655:                    "Request Queue Overflow For isp_notify_ack");
        !           656:                return;
        !           657:        }
        !           658:
        !           659:        MEMZERO(storage, QENTRY_LEN);
        !           660:
        !           661:        if (IS_FC(isp)) {
        !           662:                na_fcentry_t *na = (na_fcentry_t *) storage;
        !           663:                if (arg) {
        !           664:                        in_fcentry_t *inp = arg;
        !           665:                        MEMCPY(storage, arg, sizeof (isphdr_t));
        !           666:                        na->na_iid = inp->in_iid;
        !           667:                        if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {
        !           668:                                na->na_lun = inp->in_scclun;
        !           669:                        } else {
        !           670:                                na->na_lun = inp->in_lun;
        !           671:                        }
        !           672:                        na->na_task_flags = inp->in_task_flags;
        !           673:                        na->na_seqid = inp->in_seqid;
        !           674:                        na->na_flags = NAFC_RCOUNT;
        !           675:                        na->na_status = inp->in_status;
        !           676:                        if (inp->in_status == IN_RESET) {
        !           677:                                na->na_flags |= NAFC_RST_CLRD;
        !           678:                        }
        !           679:                } else {
        !           680:                        na->na_flags = NAFC_RST_CLRD;
        !           681:                }
        !           682:                na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK;
        !           683:                na->na_header.rqs_entry_count = 1;
        !           684:                isp_put_notify_ack_fc(isp, na, (na_fcentry_t *)outp);
        !           685:        } else {
        !           686:                na_entry_t *na = (na_entry_t *) storage;
        !           687:                if (arg) {
        !           688:                        in_entry_t *inp = arg;
        !           689:                        MEMCPY(storage, arg, sizeof (isphdr_t));
        !           690:                        na->na_iid = inp->in_iid;
        !           691:                        na->na_lun = inp->in_lun;
        !           692:                        na->na_tgt = inp->in_tgt;
        !           693:                        na->na_seqid = inp->in_seqid;
        !           694:                        if (inp->in_status == IN_RESET) {
        !           695:                                na->na_event = NA_RST_CLRD;
        !           696:                        }
        !           697:                } else {
        !           698:                        na->na_event = NA_RST_CLRD;
        !           699:                }
        !           700:                na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK;
        !           701:                na->na_header.rqs_entry_count = 1;
        !           702:                isp_put_notify_ack(isp, na, (na_entry_t *)outp);
        !           703:        }
        !           704:        ISP_TDQE(isp, "isp_notify_ack", (int) optr, storage);
        !           705:        ISP_ADD_REQUEST(isp, nxti);
        !           706: }
        !           707:
        !           708: static void
        !           709: isp_handle_atio(struct ispsoftc *isp, at_entry_t *aep)
        !           710: {
        !           711:        int lun;
        !           712:        lun = aep->at_lun;
        !           713:        /*
        !           714:         * The firmware status (except for the QLTM_SVALID bit) indicates
        !           715:         * why this ATIO was sent to us.
        !           716:         *
        !           717:         * If QLTM_SVALID is set, the firmware has recommended Sense Data.
        !           718:         *
        !           719:         * If the DISCONNECTS DISABLED bit is set in the flags field,
        !           720:         * we're still connected on the SCSI bus - i.e. the initiator
        !           721:         * did not set DiscPriv in the identify message. We don't care
        !           722:         * about this so it's ignored.
        !           723:         */
        !           724:
        !           725:        switch(aep->at_status & ~QLTM_SVALID) {
        !           726:        case AT_PATH_INVALID:
        !           727:                /*
        !           728:                 * ATIO rejected by the firmware due to disabled lun.
        !           729:                 */
        !           730:                isp_prt(isp, ISP_LOGERR,
        !           731:                    "rejected ATIO for disabled lun %d", lun);
        !           732:                break;
        !           733:        case AT_NOCAP:
        !           734:                /*
        !           735:                 * Requested Capability not available
        !           736:                 * We sent an ATIO that overflowed the firmware's
        !           737:                 * command resource count.
        !           738:                 */
        !           739:                isp_prt(isp, ISP_LOGERR,
        !           740:                    "rejected ATIO for lun %d because of command count"
        !           741:                    " overflow", lun);
        !           742:                break;
        !           743:
        !           744:        case AT_BDR_MSG:
        !           745:                /*
        !           746:                 * If we send an ATIO to the firmware to increment
        !           747:                 * its command resource count, and the firmware is
        !           748:                 * recovering from a Bus Device Reset, it returns
        !           749:                 * the ATIO with this status. We set the command
        !           750:                 * resource count in the Enable Lun entry and do
        !           751:                 * not increment it. Therefore we should never get
        !           752:                 * this status here.
        !           753:                 */
        !           754:                isp_prt(isp, ISP_LOGERR, atiocope, lun,
        !           755:                    GET_BUS_VAL(aep->at_iid));
        !           756:                break;
        !           757:
        !           758:        case AT_CDB:            /* Got a CDB */
        !           759:        case AT_PHASE_ERROR:    /* Bus Phase Sequence Error */
        !           760:                /*
        !           761:                 * Punt to platform specific layer.
        !           762:                 */
        !           763:                (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep);
        !           764:                break;
        !           765:
        !           766:        case AT_RESET:
        !           767:                /*
        !           768:                 * A bus reset came along and blew away this command. Why
        !           769:                 * they do this in addition the async event code stuff,
        !           770:                 * I dunno.
        !           771:                 *
        !           772:                 * Ignore it because the async event will clear things
        !           773:                 * up for us.
        !           774:                 */
        !           775:                isp_prt(isp, ISP_LOGWARN, atior, lun,
        !           776:                    GET_IID_VAL(aep->at_iid), GET_BUS_VAL(aep->at_iid));
        !           777:                break;
        !           778:
        !           779:
        !           780:        default:
        !           781:                isp_prt(isp, ISP_LOGERR,
        !           782:                    "Unknown ATIO status 0x%x from initiator %d for lun %d",
        !           783:                    aep->at_status, aep->at_iid, lun);
        !           784:                (void) isp_target_put_atio(isp, aep);
        !           785:                break;
        !           786:        }
        !           787: }
        !           788:
        !           789: static void
        !           790: isp_handle_atio2(struct ispsoftc *isp, at2_entry_t *aep)
        !           791: {
        !           792:        int lun;
        !           793:
        !           794:        if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) {
        !           795:                lun = aep->at_scclun;
        !           796:        } else {
        !           797:                lun = aep->at_lun;
        !           798:        }
        !           799:
        !           800:        /*
        !           801:         * The firmware status (except for the QLTM_SVALID bit) indicates
        !           802:         * why this ATIO was sent to us.
        !           803:         *
        !           804:         * If QLTM_SVALID is set, the firmware has recommended Sense Data.
        !           805:         *
        !           806:         * If the DISCONNECTS DISABLED bit is set in the flags field,
        !           807:         * we're still connected on the SCSI bus - i.e. the initiator
        !           808:         * did not set DiscPriv in the identify message. We don't care
        !           809:         * about this so it's ignored.
        !           810:         */
        !           811:
        !           812:        switch(aep->at_status & ~QLTM_SVALID) {
        !           813:        case AT_PATH_INVALID:
        !           814:                /*
        !           815:                 * ATIO rejected by the firmware due to disabled lun.
        !           816:                 */
        !           817:                isp_prt(isp, ISP_LOGERR,
        !           818:                    "rejected ATIO2 for disabled lun %d", lun);
        !           819:                break;
        !           820:        case AT_NOCAP:
        !           821:                /*
        !           822:                 * Requested Capability not available
        !           823:                 * We sent an ATIO that overflowed the firmware's
        !           824:                 * command resource count.
        !           825:                 */
        !           826:                isp_prt(isp, ISP_LOGERR,
        !           827:                    "rejected ATIO2 for lun %d- command count overflow", lun);
        !           828:                break;
        !           829:
        !           830:        case AT_BDR_MSG:
        !           831:                /*
        !           832:                 * If we send an ATIO to the firmware to increment
        !           833:                 * its command resource count, and the firmware is
        !           834:                 * recovering from a Bus Device Reset, it returns
        !           835:                 * the ATIO with this status. We set the command
        !           836:                 * resource count in the Enable Lun entry and no
        !           837:                 * not increment it. Therefore we should never get
        !           838:                 * this status here.
        !           839:                 */
        !           840:                isp_prt(isp, ISP_LOGERR, atiocope, lun, 0);
        !           841:                break;
        !           842:
        !           843:        case AT_CDB:            /* Got a CDB */
        !           844:                /*
        !           845:                 * Punt to platform specific layer.
        !           846:                 */
        !           847:                (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep);
        !           848:                break;
        !           849:
        !           850:        case AT_RESET:
        !           851:                /*
        !           852:                 * A bus reset came along an blew away this command. Why
        !           853:                 * they do this in addition the async event code stuff,
        !           854:                 * I dunno.
        !           855:                 *
        !           856:                 * Ignore it because the async event will clear things
        !           857:                 * up for us.
        !           858:                 */
        !           859:                isp_prt(isp, ISP_LOGERR, atior, lun, aep->at_iid, 0);
        !           860:                break;
        !           861:
        !           862:
        !           863:        default:
        !           864:                isp_prt(isp, ISP_LOGERR,
        !           865:                    "Unknown ATIO2 status 0x%x from initiator %d for lun %d",
        !           866:                    aep->at_status, aep->at_iid, lun);
        !           867:                (void) isp_target_put_atio(isp, aep);
        !           868:                break;
        !           869:        }
        !           870: }
        !           871:
        !           872: static void
        !           873: isp_handle_ctio(struct ispsoftc *isp, ct_entry_t *ct)
        !           874: {
        !           875:        void *xs;
        !           876:        int pl = ISP_LOGTDEBUG2;
        !           877:        char *fmsg = NULL;
        !           878:
        !           879:        if (ct->ct_syshandle) {
        !           880:                xs = isp_find_xs(isp, ct->ct_syshandle);
        !           881:                if (xs == NULL)
        !           882:                        pl = ISP_LOGALL;
        !           883:        } else {
        !           884:                xs = NULL;
        !           885:        }
        !           886:
        !           887:        switch(ct->ct_status & ~QLTM_SVALID) {
        !           888:        case CT_OK:
        !           889:                /*
        !           890:                 * There are generally 3 possibilities as to why we'd get
        !           891:                 * this condition:
        !           892:                 *      We disconnected after receiving a CDB.
        !           893:                 *      We sent or received data.
        !           894:                 *      We sent status & command complete.
        !           895:                 */
        !           896:
        !           897:                if (ct->ct_flags & CT_SENDSTATUS) {
        !           898:                        break;
        !           899:                } else if ((ct->ct_flags & CT_DATAMASK) == CT_NO_DATA) {
        !           900:                        /*
        !           901:                         * Nothing to do in this case.
        !           902:                         */
        !           903:                        isp_prt(isp, pl, "CTIO- iid %d disconnected OK",
        !           904:                            ct->ct_iid);
        !           905:                        return;
        !           906:                }
        !           907:                break;
        !           908:
        !           909:        case CT_BDR_MSG:
        !           910:                /*
        !           911:                 * Bus Device Reset message received or the SCSI Bus has
        !           912:                 * been Reset; the firmware has gone to Bus Free.
        !           913:                 *
        !           914:                 * The firmware generates an async mailbox interrupt to
        !           915:                 * notify us of this and returns outstanding CTIOs with this
        !           916:                 * status. These CTIOs are handled in that same way as
        !           917:                 * CT_ABORTED ones, so just fall through here.
        !           918:                 */
        !           919:                fmsg = "Bus Device Reset";
        !           920:                /*FALLTHROUGH*/
        !           921:        case CT_RESET:
        !           922:                if (fmsg == NULL)
        !           923:                        fmsg = "Bus Reset";
        !           924:                /*FALLTHROUGH*/
        !           925:        case CT_ABORTED:
        !           926:                /*
        !           927:                 * When an Abort message is received the firmware goes to
        !           928:                 * Bus Free and returns all outstanding CTIOs with the status
        !           929:                 * set, then sends us an Immediate Notify entry.
        !           930:                 */
        !           931:                if (fmsg == NULL)
        !           932:                        fmsg = "ABORT TAG message sent by Initiator";
        !           933:
        !           934:                isp_prt(isp, ISP_LOGWARN, "CTIO destroyed by %s", fmsg);
        !           935:                break;
        !           936:
        !           937:        case CT_INVAL:
        !           938:                /*
        !           939:                 * CTIO rejected by the firmware due to disabled lun.
        !           940:                 * "Cannot Happen".
        !           941:                 */
        !           942:                isp_prt(isp, ISP_LOGERR,
        !           943:                    "Firmware rejected CTIO for disabled lun %d",
        !           944:                    ct->ct_lun);
        !           945:                break;
        !           946:
        !           947:        case CT_NOPATH:
        !           948:                /*
        !           949:                 * CTIO rejected by the firmware due "no path for the
        !           950:                 * nondisconnecting nexus specified". This means that
        !           951:                 * we tried to access the bus while a non-disconnecting
        !           952:                 * command is in process.
        !           953:                 */
        !           954:                isp_prt(isp, ISP_LOGERR,
        !           955:                    "Firmware rejected CTIO for bad nexus %d/%d/%d",
        !           956:                    ct->ct_iid, ct->ct_tgt, ct->ct_lun);
        !           957:                break;
        !           958:
        !           959:        case CT_RSELTMO:
        !           960:                fmsg = "Reselection";
        !           961:                /*FALLTHROUGH*/
        !           962:        case CT_TIMEOUT:
        !           963:                if (fmsg == NULL)
        !           964:                        fmsg = "Command";
        !           965:                isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg);
        !           966:                break;
        !           967:
        !           968:        case    CT_PANIC:
        !           969:                if (fmsg == NULL)
        !           970:                        fmsg = "Unrecoverable Error";
        !           971:                /*FALLTHROUGH*/
        !           972:        case CT_ERR:
        !           973:                if (fmsg == NULL)
        !           974:                        fmsg = "Completed with Error";
        !           975:                /*FALLTHROUGH*/
        !           976:        case CT_PHASE_ERROR:
        !           977:                if (fmsg == NULL)
        !           978:                        fmsg = "Phase Sequence Error";
        !           979:                /*FALLTHROUGH*/
        !           980:        case CT_TERMINATED:
        !           981:                if (fmsg == NULL)
        !           982:                        fmsg = "terminated by TERMINATE TRANSFER";
        !           983:                /*FALLTHROUGH*/
        !           984:        case CT_NOACK:
        !           985:                if (fmsg == NULL)
        !           986:                        fmsg = "unacknowledged Immediate Notify pending";
        !           987:                isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg);
        !           988:                break;
        !           989:        default:
        !           990:                isp_prt(isp, ISP_LOGERR, "Unknown CTIO status 0x%x",
        !           991:                    ct->ct_status & ~QLTM_SVALID);
        !           992:                break;
        !           993:        }
        !           994:
        !           995:        if (xs == NULL) {
        !           996:                /*
        !           997:                 * There may be more than one CTIO for a data transfer,
        !           998:                 * or this may be a status CTIO we're not monitoring.
        !           999:                 *
        !          1000:                 * The assumption is that they'll all be returned in the
        !          1001:                 * order we got them.
        !          1002:                 */
        !          1003:                if (ct->ct_syshandle == 0) {
        !          1004:                        if ((ct->ct_flags & CT_SENDSTATUS) == 0) {
        !          1005:                                isp_prt(isp, pl,
        !          1006:                                    "intermediate CTIO completed ok");
        !          1007:                        } else {
        !          1008:                                isp_prt(isp, pl,
        !          1009:                                    "unmonitored CTIO completed ok");
        !          1010:                        }
        !          1011:                } else {
        !          1012:                        isp_prt(isp, pl,
        !          1013:                            "NO xs for CTIO (handle 0x%x) status 0x%x",
        !          1014:                            ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID);
        !          1015:                }
        !          1016:        } else {
        !          1017:                /*
        !          1018:                 * Final CTIO completed. Release DMA resources and
        !          1019:                 * notify platform dependent layers.
        !          1020:                 */
        !          1021:                if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) {
        !          1022:                        ISP_DMAFREE(isp, xs, ct->ct_syshandle);
        !          1023:                }
        !          1024:                isp_prt(isp, pl, "final CTIO complete");
        !          1025:                /*
        !          1026:                 * The platform layer will destroy the handle if appropriate.
        !          1027:                 */
        !          1028:                (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct);
        !          1029:        }
        !          1030: }
        !          1031:
        !          1032: static void
        !          1033: isp_handle_ctio2(struct ispsoftc *isp, ct2_entry_t *ct)
        !          1034: {
        !          1035:        XS_T *xs;
        !          1036:        int pl = ISP_LOGTDEBUG2;
        !          1037:        char *fmsg = NULL;
        !          1038:
        !          1039:        if (ct->ct_syshandle) {
        !          1040:                xs = isp_find_xs(isp, ct->ct_syshandle);
        !          1041:                if (xs == NULL)
        !          1042:                        pl = ISP_LOGALL;
        !          1043:        } else {
        !          1044:                xs = NULL;
        !          1045:        }
        !          1046:
        !          1047:        switch(ct->ct_status & ~QLTM_SVALID) {
        !          1048:        case CT_BUS_ERROR:
        !          1049:                isp_prt(isp, ISP_LOGERR, "PCI DMA Bus Error");
        !          1050:                /* FALLTHROUGH */
        !          1051:        case CT_DATA_OVER:
        !          1052:        case CT_DATA_UNDER:
        !          1053:        case CT_OK:
        !          1054:                /*
        !          1055:                 * There are generally 2 possibilities as to why we'd get
        !          1056:                 * this condition:
        !          1057:                 *      We sent or received data.
        !          1058:                 *      We sent status & command complete.
        !          1059:                 */
        !          1060:
        !          1061:                break;
        !          1062:
        !          1063:        case CT_BDR_MSG:
        !          1064:                /*
        !          1065:                 * Target Reset function received.
        !          1066:                 *
        !          1067:                 * The firmware generates an async mailbox interrupt to
        !          1068:                 * notify us of this and returns outstanding CTIOs with this
        !          1069:                 * status. These CTIOs are handled in that same way as
        !          1070:                 * CT_ABORTED ones, so just fall through here.
        !          1071:                 */
        !          1072:                fmsg = "TARGET RESET Task Management Function Received";
        !          1073:                /*FALLTHROUGH*/
        !          1074:        case CT_RESET:
        !          1075:                if (fmsg == NULL)
        !          1076:                        fmsg = "LIP Reset";
        !          1077:                /*FALLTHROUGH*/
        !          1078:        case CT_ABORTED:
        !          1079:                /*
        !          1080:                 * When an Abort message is received the firmware goes to
        !          1081:                 * Bus Free and returns all outstanding CTIOs with the status
        !          1082:                 * set, then sends us an Immediate Notify entry.
        !          1083:                 */
        !          1084:                if (fmsg == NULL)
        !          1085:                        fmsg = "ABORT Task Management Function Received";
        !          1086:
        !          1087:                isp_prt(isp, ISP_LOGERR, "CTIO2 destroyed by %s", fmsg);
        !          1088:                break;
        !          1089:
        !          1090:        case CT_INVAL:
        !          1091:                /*
        !          1092:                 * CTIO rejected by the firmware - invalid data direction.
        !          1093:                 */
        !          1094:                isp_prt(isp, ISP_LOGERR, "CTIO2 had wrong data direction");
        !          1095:                break;
        !          1096:
        !          1097:        case CT_RSELTMO:
        !          1098:                fmsg = "failure to reconnect to initiator";
        !          1099:                /*FALLTHROUGH*/
        !          1100:        case CT_TIMEOUT:
        !          1101:                if (fmsg == NULL)
        !          1102:                        fmsg = "command";
        !          1103:                isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg);
        !          1104:                break;
        !          1105:
        !          1106:        case CT_ERR:
        !          1107:                fmsg = "Completed with Error";
        !          1108:                /*FALLTHROUGH*/
        !          1109:        case CT_LOGOUT:
        !          1110:                if (fmsg == NULL)
        !          1111:                        fmsg = "Port Logout";
        !          1112:                /*FALLTHROUGH*/
        !          1113:        case CT_PORTNOTAVAIL:
        !          1114:                if (fmsg == NULL)
        !          1115:                        fmsg = "Port not available";
        !          1116:        case CT_PORTCHANGED:
        !          1117:                if (fmsg == NULL)
        !          1118:                        fmsg = "Port Changed";
        !          1119:        case CT_NOACK:
        !          1120:                if (fmsg == NULL)
        !          1121:                        fmsg = "unacknowledged Immediate Notify pending";
        !          1122:                isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg);
        !          1123:                break;
        !          1124:
        !          1125:        case CT_INVRXID:
        !          1126:                /*
        !          1127:                 * CTIO rejected by the firmware because an invalid RX_ID.
        !          1128:                 * Just print a message.
        !          1129:                 */
        !          1130:                isp_prt(isp, ISP_LOGERR,
        !          1131:                    "CTIO2 completed with Invalid RX_ID 0x%x", ct->ct_rxid);
        !          1132:                break;
        !          1133:
        !          1134:        default:
        !          1135:                isp_prt(isp, ISP_LOGERR, "Unknown CTIO2 status 0x%x",
        !          1136:                    ct->ct_status & ~QLTM_SVALID);
        !          1137:                break;
        !          1138:        }
        !          1139:
        !          1140:        if (xs == NULL) {
        !          1141:                /*
        !          1142:                 * There may be more than one CTIO for a data transfer,
        !          1143:                 * or this may be a status CTIO we're not monitoring.
        !          1144:                 *
        !          1145:                 * The assumption is that they'll all be returned in the
        !          1146:                 * order we got them.
        !          1147:                 */
        !          1148:                if (ct->ct_syshandle == 0) {
        !          1149:                        if ((ct->ct_flags & CT_SENDSTATUS) == 0) {
        !          1150:                                isp_prt(isp, pl,
        !          1151:                                    "intermediate CTIO completed ok");
        !          1152:                        } else {
        !          1153:                                isp_prt(isp, pl,
        !          1154:                                    "unmonitored CTIO completed ok");
        !          1155:                        }
        !          1156:                } else {
        !          1157:                        isp_prt(isp, pl,
        !          1158:                            "NO xs for CTIO (handle 0x%x) status 0x%x",
        !          1159:                            ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID);
        !          1160:                }
        !          1161:        } else {
        !          1162:                if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) {
        !          1163:                        ISP_DMAFREE(isp, xs, ct->ct_syshandle);
        !          1164:                }
        !          1165:                if (ct->ct_flags & CT_SENDSTATUS) {
        !          1166:                        /*
        !          1167:                         * Sent status and command complete.
        !          1168:                         *
        !          1169:                         * We're now really done with this command, so we
        !          1170:                         * punt to the platform dependent layers because
        !          1171:                         * only there can we do the appropriate command
        !          1172:                         * complete thread synchronization.
        !          1173:                         */
        !          1174:                        isp_prt(isp, pl, "status CTIO complete");
        !          1175:                } else {
        !          1176:                        /*
        !          1177:                         * Final CTIO completed. Release DMA resources and
        !          1178:                         * notify platform dependent layers.
        !          1179:                         */
        !          1180:                        isp_prt(isp, pl, "data CTIO complete");
        !          1181:                }
        !          1182:                (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct);
        !          1183:                /*
        !          1184:                 * The platform layer will destroy the handle if appropriate.
        !          1185:                 */
        !          1186:        }
        !          1187: }
        !          1188: #endif

CVSweb