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