isp_target.c revision 115521
155373Smjacob/* $FreeBSD: head/sys/dev/isp/isp_target.c 115521 2003-05-31 19:49:49Z phk $ */ 255373Smjacob/* 355373Smjacob * Machine and OS Independent Target Mode Code for the Qlogic SCSI/FC adapters. 455373Smjacob * 573319Smjacob * Copyright (c) 1999, 2000, 2001 by Matthew Jacob 655373Smjacob * All rights reserved. 755373Smjacob * mjacob@feral.com 855373Smjacob * 955373Smjacob * Redistribution and use in source and binary forms, with or without 1055373Smjacob * modification, are permitted provided that the following conditions 1155373Smjacob * are met: 1255373Smjacob * 1. Redistributions of source code must retain the above copyright 1355373Smjacob * notice immediately at the beginning of the file, without modification, 1455373Smjacob * this list of conditions, and the following disclaimer. 1566189Smjacob * 2. The name of the author may not be used to endorse or promote products 1655373Smjacob * derived from this software without specific prior written permission. 1755373Smjacob * 1855373Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1955373Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2055373Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2155373Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2255373Smjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2355373Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2455373Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2555373Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2655373Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2755373Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2855373Smjacob * SUCH DAMAGE. 2955373Smjacob */ 3055373Smjacob 3155373Smjacob/* 3290224Smjacob * Bug fixes gratefully acknowledged from: 3390224Smjacob * Oded Kedem <oded@kashya.com> 3490224Smjacob */ 3590224Smjacob/* 3655373Smjacob * Include header file appropriate for platform we're building on. 3755373Smjacob */ 3855373Smjacob 3955373Smjacob#ifdef __NetBSD__ 4055373Smjacob#include <dev/ic/isp_netbsd.h> 4155373Smjacob#endif 4255373Smjacob#ifdef __FreeBSD__ 4355373Smjacob#include <dev/isp/isp_freebsd.h> 4455373Smjacob#endif 4555373Smjacob#ifdef __OpenBSD__ 4655373Smjacob#include <dev/ic/isp_openbsd.h> 4755373Smjacob#endif 4855373Smjacob#ifdef __linux__ 4955373Smjacob#include "isp_linux.h" 5055373Smjacob#endif 5155373Smjacob 5255373Smjacob#ifdef ISP_TARGET_MODE 5375196Smjacobstatic const char atiocope[] = 5483027Smjacob "ATIO returned for lun %d because it was in the middle of Bus Device Reset " 5583027Smjacob "on bus %d"; 5675196Smjacobstatic const char atior[] = 5783027Smjacob "ATIO returned on for lun %d on from IID %d because a Bus Reset occurred " 5883027Smjacob "on bus %d"; 5955373Smjacob 6075196Smjacobstatic void isp_got_msg(struct ispsoftc *, int, in_entry_t *); 6175196Smjacobstatic void isp_got_msg_fc(struct ispsoftc *, int, in_fcentry_t *); 6275196Smjacobstatic void isp_notify_ack(struct ispsoftc *, void *); 6355373Smjacobstatic void isp_handle_atio(struct ispsoftc *, at_entry_t *); 6455373Smjacobstatic void isp_handle_atio2(struct ispsoftc *, at2_entry_t *); 6555373Smjacobstatic void isp_handle_ctio(struct ispsoftc *, ct_entry_t *); 6655373Smjacobstatic void isp_handle_ctio2(struct ispsoftc *, ct2_entry_t *); 6755373Smjacob 6855373Smjacob/* 6955373Smjacob * The Qlogic driver gets an interrupt to look at response queue entries. 7055373Smjacob * Some of these are status completions for initiatior mode commands, but 7155373Smjacob * if target mode is enabled, we get a whole wad of response queue entries 7255373Smjacob * to be handled here. 7355373Smjacob * 7455373Smjacob * Basically the split into 3 main groups: Lun Enable/Modification responses, 7555373Smjacob * SCSI Command processing, and Immediate Notification events. 7655373Smjacob * 7755373Smjacob * You start by writing a request queue entry to enable target mode (and 7855373Smjacob * establish some resource limitations which you can modify later). 7955373Smjacob * The f/w responds with a LUN ENABLE or LUN MODIFY response with 8055373Smjacob * the status of this action. If the enable was successful, you can expect... 8155373Smjacob * 8255373Smjacob * Response queue entries with SCSI commands encapsulate show up in an ATIO 8355373Smjacob * (Accept Target IO) type- sometimes with enough info to stop the command at 8455373Smjacob * this level. Ultimately the driver has to feed back to the f/w's request 8555373Smjacob * queue a sequence of CTIOs (continue target I/O) that describe data to 8655373Smjacob * be moved and/or status to be sent) and finally finishing with sending 8755373Smjacob * to the f/w's response queue an ATIO which then completes the handshake 8855373Smjacob * with the f/w for that command. There's a lot of variations on this theme, 8955373Smjacob * including flags you can set in the CTIO for the Qlogic 2X00 fibre channel 9055373Smjacob * cards that 'auto-replenish' the f/w's ATIO count, but this is the basic 9155373Smjacob * gist of it. 9255373Smjacob * 9355373Smjacob * The third group that can show up in the response queue are Immediate 9455373Smjacob * Notification events. These include things like notifications of SCSI bus 9555373Smjacob * resets, or Bus Device Reset messages or other messages received. This 9672082Sasmodai * a classic oddbins area. It can get a little weird because you then turn 9755373Smjacob * around and acknowledge the Immediate Notify by writing an entry onto the 9855373Smjacob * request queue and then the f/w turns around and gives you an acknowledgement 9955373Smjacob * to *your* acknowledgement on the response queue (the idea being to let 10055373Smjacob * the f/w tell you when the event is *really* over I guess). 10155373Smjacob * 10255373Smjacob */ 10355373Smjacob 10455373Smjacob 10555373Smjacob/* 10655373Smjacob * A new response queue entry has arrived. The interrupt service code 10755373Smjacob * has already swizzled it into the platform dependent from canonical form. 10855373Smjacob * 10955373Smjacob * Because of the way this driver is designed, unfortunately most of the 11055373Smjacob * actual synchronization work has to be done in the platform specific 11155373Smjacob * code- we have no synchroniation primitives in the common code. 11255373Smjacob */ 11355373Smjacob 11455373Smjacobint 11575196Smjacobisp_target_notify(struct ispsoftc *isp, void *vptr, u_int16_t *optrp) 11655373Smjacob{ 11755373Smjacob u_int16_t status, seqid; 11855373Smjacob union { 11955373Smjacob at_entry_t *atiop; 12055373Smjacob at2_entry_t *at2iop; 12155373Smjacob ct_entry_t *ctiop; 12255373Smjacob ct2_entry_t *ct2iop; 12355373Smjacob lun_entry_t *lunenp; 12455373Smjacob in_entry_t *inotp; 12555373Smjacob in_fcentry_t *inot_fcp; 12655373Smjacob na_entry_t *nackp; 12755373Smjacob na_fcentry_t *nack_fcp; 12855373Smjacob isphdr_t *hp; 12955373Smjacob void * *vp; 13055373Smjacob#define atiop unp.atiop 13155373Smjacob#define at2iop unp.at2iop 13255373Smjacob#define ctiop unp.ctiop 13355373Smjacob#define ct2iop unp.ct2iop 13455373Smjacob#define lunenp unp.lunenp 13555373Smjacob#define inotp unp.inotp 13655373Smjacob#define inot_fcp unp.inot_fcp 13755373Smjacob#define nackp unp.nackp 13855373Smjacob#define nack_fcp unp.nack_fcp 13955373Smjacob#define hdrp unp.hp 14055373Smjacob } unp; 14187635Smjacob u_int8_t local[QENTRY_LEN]; 14298284Smjacob int bus, type, rval = 1; 14355373Smjacob 14487635Smjacob type = isp_get_response_type(isp, (isphdr_t *)vptr); 14555373Smjacob unp.vp = vptr; 14655373Smjacob 14755373Smjacob ISP_TDQE(isp, "isp_target_notify", (int) *optrp, vptr); 14855373Smjacob 14987635Smjacob switch(type) { 15055373Smjacob case RQSTYPE_ATIO: 15187635Smjacob isp_get_atio(isp, atiop, (at_entry_t *) local); 15287635Smjacob isp_handle_atio(isp, (at_entry_t *) local); 15355373Smjacob break; 15455373Smjacob case RQSTYPE_CTIO: 15587635Smjacob isp_get_ctio(isp, ctiop, (ct_entry_t *) local); 15687635Smjacob isp_handle_ctio(isp, (ct_entry_t *) local); 15755373Smjacob break; 15855373Smjacob case RQSTYPE_ATIO2: 15987635Smjacob isp_get_atio2(isp, at2iop, (at2_entry_t *) local); 16087635Smjacob isp_handle_atio2(isp, (at2_entry_t *) local); 16155373Smjacob break; 16255373Smjacob case RQSTYPE_CTIO2: 16387635Smjacob isp_get_ctio2(isp, ct2iop, (ct2_entry_t *) local); 16487635Smjacob isp_handle_ctio2(isp, (ct2_entry_t *) local); 16555373Smjacob break; 16655373Smjacob case RQSTYPE_ENABLE_LUN: 16755373Smjacob case RQSTYPE_MODIFY_LUN: 16887635Smjacob isp_get_enable_lun(isp, lunenp, (lun_entry_t *) local); 16987635Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, local); 17055373Smjacob break; 17155373Smjacob 17255373Smjacob case RQSTYPE_NOTIFY: 17355373Smjacob /* 17455373Smjacob * Either the ISP received a SCSI message it can't 17555373Smjacob * handle, or it's returning an Immed. Notify entry 17655373Smjacob * we sent. We can send Immed. Notify entries to 17755373Smjacob * increment the firmware's resource count for them 17855373Smjacob * (we set this initially in the Enable Lun entry). 17955373Smjacob */ 18057216Smjacob bus = 0; 18155373Smjacob if (IS_FC(isp)) { 18287635Smjacob isp_get_notify_fc(isp, inot_fcp, (in_fcentry_t *)local); 18387635Smjacob inot_fcp = (in_fcentry_t *) local; 18455373Smjacob status = inot_fcp->in_status; 18555373Smjacob seqid = inot_fcp->in_seqid; 18655373Smjacob } else { 18787635Smjacob isp_get_notify(isp, inotp, (in_entry_t *)local); 18887635Smjacob inotp = (in_entry_t *) local; 18955373Smjacob status = inotp->in_status & 0xff; 19055373Smjacob seqid = inotp->in_seqid; 19157216Smjacob if (IS_DUALBUS(isp)) { 19283027Smjacob bus = GET_BUS_VAL(inotp->in_iid); 19383027Smjacob SET_BUS_VAL(inotp->in_iid, 0); 19457216Smjacob } 19555373Smjacob } 19683027Smjacob isp_prt(isp, ISP_LOGTDEBUG0, 19783027Smjacob "Immediate Notify On Bus %d, status=0x%x seqid=0x%x", 19883027Smjacob bus, status, seqid); 19983027Smjacob 20083027Smjacob /* 20183027Smjacob * ACK it right away. 20283027Smjacob */ 20387635Smjacob isp_notify_ack(isp, (status == IN_RESET)? NULL : local); 20455373Smjacob switch (status) { 20555373Smjacob case IN_RESET: 20655373Smjacob (void) isp_async(isp, ISPASYNC_BUS_RESET, &bus); 20755373Smjacob break; 20855373Smjacob case IN_MSG_RECEIVED: 20955373Smjacob case IN_IDE_RECEIVED: 21055373Smjacob if (IS_FC(isp)) { 21187635Smjacob isp_got_msg_fc(isp, bus, (in_fcentry_t *)local); 21255373Smjacob } else { 21387635Smjacob isp_got_msg(isp, bus, (in_entry_t *)local); 21455373Smjacob } 21555373Smjacob break; 21655373Smjacob case IN_RSRC_UNAVAIL: 21764090Smjacob isp_prt(isp, ISP_LOGWARN, "Firmware out of ATIOs"); 21855373Smjacob break; 21998284Smjacob case IN_PORT_LOGOUT: 22055373Smjacob case IN_ABORT_TASK: 22155373Smjacob case IN_PORT_CHANGED: 22255373Smjacob case IN_GLOBAL_LOGO: 22398284Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, &local); 22455373Smjacob break; 22555373Smjacob default: 22664090Smjacob isp_prt(isp, ISP_LOGERR, 22764090Smjacob "bad status (0x%x) in isp_target_notify", status); 22855373Smjacob break; 22955373Smjacob } 23055373Smjacob break; 23155373Smjacob 23255373Smjacob case RQSTYPE_NOTIFY_ACK: 23355373Smjacob /* 23455373Smjacob * The ISP is acknowledging our acknowledgement of an 23555373Smjacob * Immediate Notify entry for some asynchronous event. 23655373Smjacob */ 23755373Smjacob if (IS_FC(isp)) { 23887635Smjacob isp_get_notify_ack_fc(isp, nack_fcp, 23987635Smjacob (na_fcentry_t *)local); 24087635Smjacob nack_fcp = (na_fcentry_t *)local; 24164090Smjacob isp_prt(isp, ISP_LOGTDEBUG1, 24264090Smjacob "Notify Ack status=0x%x seqid 0x%x", 24364090Smjacob nack_fcp->na_status, nack_fcp->na_seqid); 24455373Smjacob } else { 24587635Smjacob isp_get_notify_ack(isp, nackp, (na_entry_t *)local); 24687635Smjacob nackp = (na_entry_t *)local; 24764090Smjacob isp_prt(isp, ISP_LOGTDEBUG1, 24864090Smjacob "Notify Ack event 0x%x status=0x%x seqid 0x%x", 24964090Smjacob nackp->na_event, nackp->na_status, nackp->na_seqid); 25055373Smjacob } 25155373Smjacob break; 25255373Smjacob default: 25364090Smjacob isp_prt(isp, ISP_LOGERR, 25487635Smjacob "Unknown entry type 0x%x in isp_target_notify", type); 25598284Smjacob rval = 0; 25655373Smjacob break; 25755373Smjacob } 25855373Smjacob#undef atiop 25955373Smjacob#undef at2iop 26055373Smjacob#undef ctiop 26155373Smjacob#undef ct2iop 26255373Smjacob#undef lunenp 26355373Smjacob#undef inotp 26455373Smjacob#undef inot_fcp 26555373Smjacob#undef nackp 26655373Smjacob#undef nack_fcp 26755373Smjacob#undef hdrp 26855373Smjacob return (rval); 26955373Smjacob} 27055373Smjacob 27155373Smjacob 27255373Smjacob/* 27355373Smjacob * Toggle (on/off) target mode for bus/target/lun 27455373Smjacob * 27555373Smjacob * The caller has checked for overlap and legality. 27655373Smjacob * 27755373Smjacob * Note that not all of bus, target or lun can be paid attention to. 27855373Smjacob * Note also that this action will not be complete until the f/w writes 27955373Smjacob * response entry. The caller is responsible for synchronizing this. 28055373Smjacob */ 28155373Smjacobint 28275196Smjacobisp_lun_cmd(struct ispsoftc *isp, int cmd, int bus, int tgt, int lun, 28377365Smjacob int cmd_cnt, int inot_cnt, u_int32_t opaque) 28455373Smjacob{ 28555373Smjacob lun_entry_t el; 28687635Smjacob u_int16_t nxti, optr; 28755373Smjacob void *outp; 28855373Smjacob 28955373Smjacob 29055373Smjacob MEMZERO(&el, sizeof (el)); 29157216Smjacob if (IS_DUALBUS(isp)) { 29257216Smjacob el.le_rsvd = (bus & 0x1) << 7; 29357216Smjacob } 29477365Smjacob el.le_cmd_count = cmd_cnt; 29577365Smjacob el.le_in_count = inot_cnt; 29655373Smjacob if (cmd == RQSTYPE_ENABLE_LUN) { 29755373Smjacob if (IS_SCSI(isp)) { 29861774Smjacob el.le_flags = LUN_TQAE|LUN_DISAD; 29955373Smjacob el.le_cdb6len = 12; 30055373Smjacob el.le_cdb7len = 12; 30155373Smjacob } 30255373Smjacob } else if (cmd == -RQSTYPE_ENABLE_LUN) { 30355373Smjacob cmd = RQSTYPE_ENABLE_LUN; 30455373Smjacob el.le_cmd_count = 0; 30555373Smjacob el.le_in_count = 0; 30655373Smjacob } else if (cmd == -RQSTYPE_MODIFY_LUN) { 30755373Smjacob cmd = RQSTYPE_MODIFY_LUN; 30855373Smjacob el.le_ops = LUN_CCDECR | LUN_INDECR; 30955373Smjacob } else { 31055373Smjacob el.le_ops = LUN_CCINCR | LUN_ININCR; 31155373Smjacob } 31255373Smjacob el.le_header.rqs_entry_type = cmd; 31355373Smjacob el.le_header.rqs_entry_count = 1; 31455373Smjacob el.le_reserved = opaque; 31555373Smjacob if (IS_SCSI(isp)) { 31655373Smjacob el.le_tgt = tgt; 31755373Smjacob el.le_lun = lun; 31883027Smjacob } else if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 31955373Smjacob el.le_lun = lun; 32055373Smjacob } 32175196Smjacob el.le_timeout = 2; 32255373Smjacob 32387635Smjacob if (isp_getrqentry(isp, &nxti, &optr, &outp)) { 32487635Smjacob isp_prt(isp, ISP_LOGERR, 32564090Smjacob "Request Queue Overflow in isp_lun_cmd"); 32655373Smjacob return (-1); 32755373Smjacob } 32855373Smjacob ISP_TDQE(isp, "isp_lun_cmd", (int) optr, &el); 32987635Smjacob isp_put_enable_lun(isp, &el, outp); 33087635Smjacob ISP_ADD_REQUEST(isp, nxti); 33155373Smjacob return (0); 33255373Smjacob} 33355373Smjacob 33455373Smjacob 33555373Smjacobint 33675196Smjacobisp_target_put_entry(struct ispsoftc *isp, void *ap) 33755373Smjacob{ 33855373Smjacob void *outp; 33987635Smjacob u_int16_t nxti, optr; 34055373Smjacob u_int8_t etype = ((isphdr_t *) ap)->rqs_entry_type; 34155373Smjacob 34287635Smjacob if (isp_getrqentry(isp, &nxti, &optr, &outp)) { 34364090Smjacob isp_prt(isp, ISP_LOGWARN, 34464090Smjacob "Request Queue Overflow in isp_target_put_entry"); 34555373Smjacob return (-1); 34655373Smjacob } 34755373Smjacob switch (etype) { 34855373Smjacob case RQSTYPE_ATIO: 34987635Smjacob isp_put_atio(isp, (at_entry_t *) ap, (at_entry_t *) outp); 35055373Smjacob break; 35155373Smjacob case RQSTYPE_ATIO2: 35287635Smjacob isp_put_atio2(isp, (at2_entry_t *) ap, (at2_entry_t *) outp); 35355373Smjacob break; 35455373Smjacob case RQSTYPE_CTIO: 35587635Smjacob isp_put_ctio(isp, (ct_entry_t *) ap, (ct_entry_t *) outp); 35655373Smjacob break; 35755373Smjacob case RQSTYPE_CTIO2: 35887635Smjacob isp_put_ctio2(isp, (ct2_entry_t *) ap, (ct2_entry_t *) outp); 35955373Smjacob break; 36055373Smjacob default: 36164090Smjacob isp_prt(isp, ISP_LOGERR, 36264090Smjacob "Unknown type 0x%x in isp_put_entry", etype); 36355373Smjacob return (-1); 36455373Smjacob } 36555373Smjacob 36655373Smjacob ISP_TDQE(isp, "isp_target_put_entry", (int) optr, ap);; 36787635Smjacob ISP_ADD_REQUEST(isp, nxti); 36855373Smjacob return (0); 36955373Smjacob} 37055373Smjacob 37155373Smjacobint 37275196Smjacobisp_target_put_atio(struct ispsoftc *isp, void *arg) 37355373Smjacob{ 37455373Smjacob union { 37555373Smjacob at_entry_t _atio; 37655373Smjacob at2_entry_t _atio2; 37755373Smjacob } atun; 37855373Smjacob 37955373Smjacob MEMZERO(&atun, sizeof atun); 38055373Smjacob if (IS_FC(isp)) { 38175196Smjacob at2_entry_t *aep = arg; 38255373Smjacob atun._atio2.at_header.rqs_entry_type = RQSTYPE_ATIO2; 38355373Smjacob atun._atio2.at_header.rqs_entry_count = 1; 38482843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 38575196Smjacob atun._atio2.at_scclun = (u_int16_t) aep->at_scclun; 38661774Smjacob } else { 38782843Smjacob atun._atio2.at_lun = (u_int8_t) aep->at_lun; 38861774Smjacob } 389110973Smjacob atun._atio2.at_iid = aep->at_iid; 390111004Smjacob atun._atio2.at_rxid = aep->at_rxid; 39155373Smjacob atun._atio2.at_status = CT_OK; 39255373Smjacob } else { 39375196Smjacob at_entry_t *aep = arg; 39455373Smjacob atun._atio.at_header.rqs_entry_type = RQSTYPE_ATIO; 39555373Smjacob atun._atio.at_header.rqs_entry_count = 1; 39675196Smjacob atun._atio.at_handle = aep->at_handle; 39775196Smjacob atun._atio.at_iid = aep->at_iid; 39875196Smjacob atun._atio.at_tgt = aep->at_tgt; 39975196Smjacob atun._atio.at_lun = aep->at_lun; 40075196Smjacob atun._atio.at_tag_type = aep->at_tag_type; 40175196Smjacob atun._atio.at_tag_val = aep->at_tag_val; 40275196Smjacob atun._atio.at_status = (aep->at_flags & AT_TQAE); 40375196Smjacob atun._atio.at_status |= CT_OK; 40455373Smjacob } 40555373Smjacob return (isp_target_put_entry(isp, &atun)); 40655373Smjacob} 40755373Smjacob 40855373Smjacob/* 40955373Smjacob * Command completion- both for handling cases of no resources or 41055373Smjacob * no blackhole driver, or other cases where we have to, inline, 41155373Smjacob * finish the command sanely, or for normal command completion. 41255373Smjacob * 41355373Smjacob * The 'completion' code value has the scsi status byte in the low 8 bits. 41455373Smjacob * If status is a CHECK CONDITION and bit 8 is nonzero, then bits 12..15 have 41555373Smjacob * the sense key and bits 16..23 have the ASCQ and bits 24..31 have the ASC 41655373Smjacob * values. 41755373Smjacob * 41855373Smjacob * NB: the key, asc, ascq, cannot be used for parallel SCSI as it doesn't 41975196Smjacob * NB: inline SCSI sense reporting. As such, we lose this information. XXX. 42055373Smjacob * 42155373Smjacob * For both parallel && fibre channel, we use the feature that does 42255373Smjacob * an automatic resource autoreplenish so we don't have then later do 42355373Smjacob * put of an atio to replenish the f/w's resource count. 42455373Smjacob */ 42555373Smjacob 42655373Smjacobint 42773319Smjacobisp_endcmd(struct ispsoftc *isp, void *arg, u_int32_t code, u_int16_t hdl) 42855373Smjacob{ 42955373Smjacob int sts; 43055373Smjacob union { 43155373Smjacob ct_entry_t _ctio; 43255373Smjacob ct2_entry_t _ctio2; 43355373Smjacob } un; 43455373Smjacob 43555373Smjacob MEMZERO(&un, sizeof un); 43655373Smjacob sts = code & 0xff; 43755373Smjacob 43855373Smjacob if (IS_FC(isp)) { 43955373Smjacob at2_entry_t *aep = arg; 44055373Smjacob ct2_entry_t *cto = &un._ctio2; 44155373Smjacob 44255373Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 44355373Smjacob cto->ct_header.rqs_entry_count = 1; 44455373Smjacob cto->ct_iid = aep->at_iid; 44583027Smjacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 44661774Smjacob cto->ct_lun = aep->at_lun; 44761774Smjacob } 44855373Smjacob cto->ct_rxid = aep->at_rxid; 44956006Smjacob cto->rsp.m1.ct_scsi_status = sts & 0xff; 45055373Smjacob cto->ct_flags = CT2_SENDSTATUS | CT2_NO_DATA | CT2_FLAG_MODE1; 45155373Smjacob if (hdl == 0) { 45255373Smjacob cto->ct_flags |= CT2_CCINCR; 45355373Smjacob } 45455373Smjacob if (aep->at_datalen) { 45555373Smjacob cto->ct_resid = aep->at_datalen; 45677365Smjacob cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER; 45755373Smjacob } 45856006Smjacob if ((sts & 0xff) == SCSI_CHECK && (sts & ECMD_SVALID)) { 45955373Smjacob cto->rsp.m1.ct_resp[0] = 0xf0; 46055373Smjacob cto->rsp.m1.ct_resp[2] = (code >> 12) & 0xf; 46155373Smjacob cto->rsp.m1.ct_resp[7] = 8; 46255373Smjacob cto->rsp.m1.ct_resp[12] = (code >> 24) & 0xff; 46355373Smjacob cto->rsp.m1.ct_resp[13] = (code >> 16) & 0xff; 46455373Smjacob cto->rsp.m1.ct_senselen = 16; 46577365Smjacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 46655373Smjacob } 46774232Smjacob cto->ct_syshandle = hdl; 46855373Smjacob } else { 46955373Smjacob at_entry_t *aep = arg; 47055373Smjacob ct_entry_t *cto = &un._ctio; 47155373Smjacob 47255373Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 47355373Smjacob cto->ct_header.rqs_entry_count = 1; 47473319Smjacob cto->ct_fwhandle = aep->at_handle; 47555373Smjacob cto->ct_iid = aep->at_iid; 47655373Smjacob cto->ct_tgt = aep->at_tgt; 47755373Smjacob cto->ct_lun = aep->at_lun; 47855373Smjacob cto->ct_tag_type = aep->at_tag_type; 47955373Smjacob cto->ct_tag_val = aep->at_tag_val; 48075196Smjacob if (aep->at_flags & AT_TQAE) { 48175196Smjacob cto->ct_flags |= CT_TQAE; 48275196Smjacob } 48355373Smjacob cto->ct_flags = CT_SENDSTATUS | CT_NO_DATA; 48455373Smjacob if (hdl == 0) { 48555373Smjacob cto->ct_flags |= CT_CCINCR; 48655373Smjacob } 48755373Smjacob cto->ct_scsi_status = sts; 48874232Smjacob cto->ct_syshandle = hdl; 48955373Smjacob } 49055373Smjacob return (isp_target_put_entry(isp, &un)); 49155373Smjacob} 49255373Smjacob 49398284Smjacobint 49475196Smjacobisp_target_async(struct ispsoftc *isp, int bus, int event) 49555373Smjacob{ 49655373Smjacob tmd_event_t evt; 49755373Smjacob tmd_msg_t msg; 49855373Smjacob 49955373Smjacob switch (event) { 50055373Smjacob /* 50155373Smjacob * These three we handle here to propagate an effective bus reset 50255373Smjacob * upstream, but these do not require any immediate notify actions 50355373Smjacob * so we return when done. 50455373Smjacob */ 50583027Smjacob case ASYNC_LIP_F8: 50655373Smjacob case ASYNC_LIP_OCCURRED: 50755373Smjacob case ASYNC_LOOP_UP: 50855373Smjacob case ASYNC_LOOP_DOWN: 50983027Smjacob case ASYNC_LOOP_RESET: 51083027Smjacob case ASYNC_PTPMODE: 51183027Smjacob /* 51283027Smjacob * These don't require any immediate notify actions. We used 51383027Smjacob * treat them like SCSI Bus Resets, but that was just plain 51483027Smjacob * wrong. Let the normal CTIO completion report what occurred. 51583027Smjacob */ 51698284Smjacob return (0); 51755373Smjacob 51855373Smjacob case ASYNC_BUS_RESET: 51955373Smjacob case ASYNC_TIMEOUT_RESET: 52055373Smjacob if (IS_FC(isp)) { 52198284Smjacob return (0); /* we'll be getting an inotify instead */ 52255373Smjacob } 52355373Smjacob evt.ev_bus = bus; 52455373Smjacob evt.ev_event = event; 52555373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_EVENT, &evt); 52655373Smjacob break; 52755373Smjacob case ASYNC_DEVICE_RESET: 52855373Smjacob /* 52955373Smjacob * Bus Device Reset resets a specific target, so 53055373Smjacob * we pass this as a synthesized message. 53155373Smjacob */ 53255373Smjacob MEMZERO(&msg, sizeof msg); 53355373Smjacob if (IS_FC(isp)) { 53465140Smjacob msg.nt_iid = FCPARAM(isp)->isp_loopid; 53555373Smjacob } else { 53665140Smjacob msg.nt_iid = SDPARAM(isp)->isp_initiator_id; 53755373Smjacob } 53855373Smjacob msg.nt_bus = bus; 53955373Smjacob msg.nt_msg[0] = MSG_BUS_DEV_RESET; 54055373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg); 54155373Smjacob break; 54255373Smjacob default: 54364090Smjacob isp_prt(isp, ISP_LOGERR, 54464090Smjacob "isp_target_async: unknown event 0x%x", event); 54555373Smjacob break; 54655373Smjacob } 54763388Smjacob if (isp->isp_state == ISP_RUNSTATE) 54863388Smjacob isp_notify_ack(isp, NULL); 54998284Smjacob return(0); 55055373Smjacob} 55155373Smjacob 55255373Smjacob 55355373Smjacob/* 55455373Smjacob * Process a received message. 55555373Smjacob * The ISP firmware can handle most messages, there are only 55655373Smjacob * a few that we need to deal with: 55755373Smjacob * - abort: clean up the current command 55855373Smjacob * - abort tag and clear queue 55955373Smjacob */ 56055373Smjacob 56155373Smjacobstatic void 56275196Smjacobisp_got_msg(struct ispsoftc *isp, int bus, in_entry_t *inp) 56355373Smjacob{ 56455373Smjacob u_int8_t status = inp->in_status & ~QLTM_SVALID; 56555373Smjacob 56655373Smjacob if (status == IN_IDE_RECEIVED || status == IN_MSG_RECEIVED) { 56755373Smjacob tmd_msg_t msg; 56855373Smjacob 56955373Smjacob MEMZERO(&msg, sizeof (msg)); 57055373Smjacob msg.nt_bus = bus; 57155373Smjacob msg.nt_iid = inp->in_iid; 57255373Smjacob msg.nt_tgt = inp->in_tgt; 57355373Smjacob msg.nt_lun = inp->in_lun; 57455373Smjacob msg.nt_tagtype = inp->in_tag_type; 57555373Smjacob msg.nt_tagval = inp->in_tag_val; 57655373Smjacob MEMCPY(msg.nt_msg, inp->in_msg, IN_MSGLEN); 57755373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg); 57855373Smjacob } else { 57964090Smjacob isp_prt(isp, ISP_LOGERR, 58064090Smjacob "unknown immediate notify status 0x%x", inp->in_status); 58155373Smjacob } 58255373Smjacob} 58355373Smjacob 58455373Smjacob/* 58555373Smjacob * Synthesize a message from the task management flags in a FCP_CMND_IU. 58655373Smjacob */ 58755373Smjacobstatic void 58875196Smjacobisp_got_msg_fc(struct ispsoftc *isp, int bus, in_fcentry_t *inp) 58955373Smjacob{ 59082843Smjacob int lun; 59175196Smjacob static const char f1[] = "%s from iid %d lun %d seq 0x%x"; 59275196Smjacob static const char f2[] = 59364090Smjacob "unknown %s 0x%x lun %d iid %d task flags 0x%x seq 0x%x\n"; 59455373Smjacob 59582843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 59682843Smjacob lun = inp->in_scclun; 59782843Smjacob } else { 59882843Smjacob lun = inp->in_lun; 59982843Smjacob } 60082843Smjacob 60155373Smjacob if (inp->in_status != IN_MSG_RECEIVED) { 60264090Smjacob isp_prt(isp, ISP_LOGINFO, f2, "immediate notify status", 60382843Smjacob inp->in_status, lun, inp->in_iid, 60455373Smjacob inp->in_task_flags, inp->in_seqid); 60555373Smjacob } else { 60655373Smjacob tmd_msg_t msg; 60755373Smjacob 60855373Smjacob MEMZERO(&msg, sizeof (msg)); 60955373Smjacob msg.nt_bus = bus; 61055373Smjacob msg.nt_iid = inp->in_iid; 61155373Smjacob msg.nt_tagval = inp->in_seqid; 61282843Smjacob msg.nt_lun = lun; 61355373Smjacob 61455373Smjacob if (inp->in_task_flags & TASK_FLAGS_ABORT_TASK) { 61564090Smjacob isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK", 616105134Smjacob inp->in_iid, lun, inp->in_seqid); 61755373Smjacob msg.nt_msg[0] = MSG_ABORT_TAG; 61855373Smjacob } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_TASK_SET) { 61964090Smjacob isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET", 620105134Smjacob inp->in_iid, lun, inp->in_seqid); 62155373Smjacob msg.nt_msg[0] = MSG_CLEAR_QUEUE; 62255373Smjacob } else if (inp->in_task_flags & TASK_FLAGS_TARGET_RESET) { 62364090Smjacob isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET", 624105134Smjacob inp->in_iid, lun, inp->in_seqid); 62555373Smjacob msg.nt_msg[0] = MSG_BUS_DEV_RESET; 62655373Smjacob } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_ACA) { 62764090Smjacob isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA", 628105134Smjacob inp->in_iid, lun, inp->in_seqid); 62955373Smjacob /* ???? */ 63055373Smjacob msg.nt_msg[0] = MSG_REL_RECOVERY; 63155373Smjacob } else if (inp->in_task_flags & TASK_FLAGS_TERMINATE_TASK) { 63264090Smjacob isp_prt(isp, ISP_LOGINFO, f1, "TERMINATE TASK", 633105134Smjacob inp->in_iid, lun, inp->in_seqid); 63455373Smjacob msg.nt_msg[0] = MSG_TERM_IO_PROC; 63555373Smjacob } else { 63664090Smjacob isp_prt(isp, ISP_LOGWARN, f2, "task flag", 637105134Smjacob inp->in_status, lun, inp->in_iid, 63855373Smjacob inp->in_task_flags, inp->in_seqid); 63955373Smjacob } 64055373Smjacob if (msg.nt_msg[0]) { 64155373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg); 64255373Smjacob } 64355373Smjacob } 64455373Smjacob} 64555373Smjacob 64655373Smjacobstatic void 64775196Smjacobisp_notify_ack(struct ispsoftc *isp, void *arg) 64855373Smjacob{ 64955373Smjacob char storage[QENTRY_LEN]; 65087635Smjacob u_int16_t nxti, optr; 65155373Smjacob void *outp; 65255373Smjacob 65387635Smjacob if (isp_getrqentry(isp, &nxti, &optr, &outp)) { 65464090Smjacob isp_prt(isp, ISP_LOGWARN, 65564090Smjacob "Request Queue Overflow For isp_notify_ack"); 65655373Smjacob return; 65755373Smjacob } 65855373Smjacob 65956006Smjacob MEMZERO(storage, QENTRY_LEN); 66055373Smjacob 66155373Smjacob if (IS_FC(isp)) { 66255373Smjacob na_fcentry_t *na = (na_fcentry_t *) storage; 66355373Smjacob if (arg) { 66455373Smjacob in_fcentry_t *inp = arg; 66556006Smjacob MEMCPY(storage, arg, sizeof (isphdr_t)); 66655373Smjacob na->na_iid = inp->in_iid; 66782843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 66861774Smjacob na->na_lun = inp->in_scclun; 66961774Smjacob } else { 67061774Smjacob na->na_lun = inp->in_lun; 67161774Smjacob } 67255373Smjacob na->na_task_flags = inp->in_task_flags; 67355373Smjacob na->na_seqid = inp->in_seqid; 67455373Smjacob na->na_flags = NAFC_RCOUNT; 67590224Smjacob na->na_status = inp->in_status; 67655373Smjacob if (inp->in_status == IN_RESET) { 67755373Smjacob na->na_flags |= NAFC_RST_CLRD; 67855373Smjacob } 67955373Smjacob } else { 68055373Smjacob na->na_flags = NAFC_RST_CLRD; 68155373Smjacob } 68259453Smjacob na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; 68359453Smjacob na->na_header.rqs_entry_count = 1; 68487635Smjacob isp_put_notify_ack_fc(isp, na, (na_fcentry_t *)outp); 68555373Smjacob } else { 68655373Smjacob na_entry_t *na = (na_entry_t *) storage; 68755373Smjacob if (arg) { 68855373Smjacob in_entry_t *inp = arg; 68956006Smjacob MEMCPY(storage, arg, sizeof (isphdr_t)); 69055373Smjacob na->na_iid = inp->in_iid; 69155373Smjacob na->na_lun = inp->in_lun; 69255373Smjacob na->na_tgt = inp->in_tgt; 69355373Smjacob na->na_seqid = inp->in_seqid; 69455373Smjacob if (inp->in_status == IN_RESET) { 69559453Smjacob na->na_event = NA_RST_CLRD; 69655373Smjacob } 69755373Smjacob } else { 69859453Smjacob na->na_event = NA_RST_CLRD; 69955373Smjacob } 70059453Smjacob na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; 70159453Smjacob na->na_header.rqs_entry_count = 1; 70287635Smjacob isp_put_notify_ack(isp, na, (na_entry_t *)outp); 70355373Smjacob } 70455373Smjacob ISP_TDQE(isp, "isp_notify_ack", (int) optr, storage); 70587635Smjacob ISP_ADD_REQUEST(isp, nxti); 70655373Smjacob} 70755373Smjacob 70855373Smjacobstatic void 70975196Smjacobisp_handle_atio(struct ispsoftc *isp, at_entry_t *aep) 71055373Smjacob{ 71155373Smjacob int lun; 71255373Smjacob lun = aep->at_lun; 71355373Smjacob /* 71455373Smjacob * The firmware status (except for the QLTM_SVALID bit) indicates 71555373Smjacob * why this ATIO was sent to us. 71655373Smjacob * 71755373Smjacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 71855373Smjacob * 71955373Smjacob * If the DISCONNECTS DISABLED bit is set in the flags field, 72055373Smjacob * we're still connected on the SCSI bus - i.e. the initiator 72155373Smjacob * did not set DiscPriv in the identify message. We don't care 72255373Smjacob * about this so it's ignored. 72355373Smjacob */ 72455373Smjacob 72555373Smjacob switch(aep->at_status & ~QLTM_SVALID) { 72655373Smjacob case AT_PATH_INVALID: 72755373Smjacob /* 72855373Smjacob * ATIO rejected by the firmware due to disabled lun. 72955373Smjacob */ 73064090Smjacob isp_prt(isp, ISP_LOGERR, 73164090Smjacob "rejected ATIO for disabled lun %d", lun); 73255373Smjacob break; 73355373Smjacob case AT_NOCAP: 73455373Smjacob /* 73555373Smjacob * Requested Capability not available 73655373Smjacob * We sent an ATIO that overflowed the firmware's 73755373Smjacob * command resource count. 73855373Smjacob */ 73964090Smjacob isp_prt(isp, ISP_LOGERR, 74064090Smjacob "rejected ATIO for lun %d because of command count" 74164090Smjacob " overflow", lun); 74255373Smjacob break; 74355373Smjacob 74455373Smjacob case AT_BDR_MSG: 74555373Smjacob /* 74655373Smjacob * If we send an ATIO to the firmware to increment 74755373Smjacob * its command resource count, and the firmware is 74855373Smjacob * recovering from a Bus Device Reset, it returns 74955373Smjacob * the ATIO with this status. We set the command 75087635Smjacob * resource count in the Enable Lun entry and do 75155373Smjacob * not increment it. Therefore we should never get 75255373Smjacob * this status here. 75355373Smjacob */ 75483027Smjacob isp_prt(isp, ISP_LOGERR, atiocope, lun, 75583027Smjacob GET_BUS_VAL(aep->at_iid)); 75655373Smjacob break; 75755373Smjacob 75855373Smjacob case AT_CDB: /* Got a CDB */ 75955373Smjacob case AT_PHASE_ERROR: /* Bus Phase Sequence Error */ 76055373Smjacob /* 76155373Smjacob * Punt to platform specific layer. 76255373Smjacob */ 76355373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep); 76455373Smjacob break; 76555373Smjacob 76655373Smjacob case AT_RESET: 76755373Smjacob /* 768108470Sschweikh * A bus reset came along and blew away this command. Why 76955373Smjacob * they do this in addition the async event code stuff, 77055373Smjacob * I dunno. 77155373Smjacob * 77255373Smjacob * Ignore it because the async event will clear things 77355373Smjacob * up for us. 77455373Smjacob */ 77583027Smjacob isp_prt(isp, ISP_LOGWARN, atior, lun, 77683027Smjacob GET_IID_VAL(aep->at_iid), GET_BUS_VAL(aep->at_iid)); 77755373Smjacob break; 77855373Smjacob 77955373Smjacob 78055373Smjacob default: 78164090Smjacob isp_prt(isp, ISP_LOGERR, 78264090Smjacob "Unknown ATIO status 0x%x from initiator %d for lun %d", 78364090Smjacob aep->at_status, aep->at_iid, lun); 78475196Smjacob (void) isp_target_put_atio(isp, aep); 78555373Smjacob break; 78655373Smjacob } 78755373Smjacob} 78855373Smjacob 78955373Smjacobstatic void 79075196Smjacobisp_handle_atio2(struct ispsoftc *isp, at2_entry_t *aep) 79155373Smjacob{ 79255373Smjacob int lun; 79361774Smjacob 79482843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 79561774Smjacob lun = aep->at_scclun; 79661774Smjacob } else { 79761774Smjacob lun = aep->at_lun; 79861774Smjacob } 79961774Smjacob 80055373Smjacob /* 80155373Smjacob * The firmware status (except for the QLTM_SVALID bit) indicates 80255373Smjacob * why this ATIO was sent to us. 80355373Smjacob * 80455373Smjacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 80555373Smjacob * 80655373Smjacob * If the DISCONNECTS DISABLED bit is set in the flags field, 80755373Smjacob * we're still connected on the SCSI bus - i.e. the initiator 80855373Smjacob * did not set DiscPriv in the identify message. We don't care 80955373Smjacob * about this so it's ignored. 81055373Smjacob */ 81155373Smjacob 81255373Smjacob switch(aep->at_status & ~QLTM_SVALID) { 81355373Smjacob case AT_PATH_INVALID: 81455373Smjacob /* 81555373Smjacob * ATIO rejected by the firmware due to disabled lun. 81655373Smjacob */ 81764090Smjacob isp_prt(isp, ISP_LOGERR, 81864090Smjacob "rejected ATIO2 for disabled lun %d", lun); 81955373Smjacob break; 82055373Smjacob case AT_NOCAP: 82155373Smjacob /* 82255373Smjacob * Requested Capability not available 82355373Smjacob * We sent an ATIO that overflowed the firmware's 82455373Smjacob * command resource count. 82555373Smjacob */ 82664090Smjacob isp_prt(isp, ISP_LOGERR, 82764090Smjacob "rejected ATIO2 for lun %d- command count overflow", lun); 82855373Smjacob break; 82955373Smjacob 83055373Smjacob case AT_BDR_MSG: 83155373Smjacob /* 83255373Smjacob * If we send an ATIO to the firmware to increment 83355373Smjacob * its command resource count, and the firmware is 83455373Smjacob * recovering from a Bus Device Reset, it returns 83555373Smjacob * the ATIO with this status. We set the command 83655373Smjacob * resource count in the Enable Lun entry and no 83755373Smjacob * not increment it. Therefore we should never get 83855373Smjacob * this status here. 83955373Smjacob */ 84083027Smjacob isp_prt(isp, ISP_LOGERR, atiocope, lun, 0); 84155373Smjacob break; 84255373Smjacob 84355373Smjacob case AT_CDB: /* Got a CDB */ 84455373Smjacob /* 84555373Smjacob * Punt to platform specific layer. 84655373Smjacob */ 84755373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep); 84855373Smjacob break; 84955373Smjacob 85055373Smjacob case AT_RESET: 85155373Smjacob /* 85255373Smjacob * A bus reset came along an blew away this command. Why 85355373Smjacob * they do this in addition the async event code stuff, 85455373Smjacob * I dunno. 85555373Smjacob * 85655373Smjacob * Ignore it because the async event will clear things 85755373Smjacob * up for us. 85855373Smjacob */ 85983027Smjacob isp_prt(isp, ISP_LOGERR, atior, lun, aep->at_iid, 0); 86055373Smjacob break; 86155373Smjacob 86255373Smjacob 86355373Smjacob default: 86464090Smjacob isp_prt(isp, ISP_LOGERR, 86564090Smjacob "Unknown ATIO2 status 0x%x from initiator %d for lun %d", 86664090Smjacob aep->at_status, aep->at_iid, lun); 86775196Smjacob (void) isp_target_put_atio(isp, aep); 86855373Smjacob break; 86955373Smjacob } 87055373Smjacob} 87155373Smjacob 87255373Smjacobstatic void 87375196Smjacobisp_handle_ctio(struct ispsoftc *isp, ct_entry_t *ct) 87455373Smjacob{ 87574232Smjacob void *xs; 87664090Smjacob int pl = ISP_LOGTDEBUG2; 87755373Smjacob char *fmsg = NULL; 87855373Smjacob 87974232Smjacob if (ct->ct_syshandle) { 88074232Smjacob xs = isp_find_xs(isp, ct->ct_syshandle); 88155373Smjacob if (xs == NULL) 88264090Smjacob pl = ISP_LOGALL; 88355373Smjacob } else { 88455373Smjacob xs = NULL; 88555373Smjacob } 88655373Smjacob 88755373Smjacob switch(ct->ct_status & ~QLTM_SVALID) { 88855373Smjacob case CT_OK: 88955373Smjacob /* 89055373Smjacob * There are generally 3 possibilities as to why we'd get 89155373Smjacob * this condition: 89255373Smjacob * We disconnected after receiving a CDB. 89355373Smjacob * We sent or received data. 89455373Smjacob * We sent status & command complete. 89555373Smjacob */ 89655373Smjacob 89759453Smjacob if (ct->ct_flags & CT_SENDSTATUS) { 89859453Smjacob break; 89959453Smjacob } else if ((ct->ct_flags & CT_DATAMASK) == CT_NO_DATA) { 90055373Smjacob /* 90155373Smjacob * Nothing to do in this case. 90255373Smjacob */ 90364090Smjacob isp_prt(isp, pl, "CTIO- iid %d disconnected OK", 90464090Smjacob ct->ct_iid); 90555373Smjacob return; 90655373Smjacob } 90755373Smjacob break; 90855373Smjacob 90955373Smjacob case CT_BDR_MSG: 91055373Smjacob /* 91155373Smjacob * Bus Device Reset message received or the SCSI Bus has 91255373Smjacob * been Reset; the firmware has gone to Bus Free. 91355373Smjacob * 91455373Smjacob * The firmware generates an async mailbox interupt to 91555373Smjacob * notify us of this and returns outstanding CTIOs with this 91655373Smjacob * status. These CTIOs are handled in that same way as 91755373Smjacob * CT_ABORTED ones, so just fall through here. 91855373Smjacob */ 91955373Smjacob fmsg = "Bus Device Reset"; 92055373Smjacob /*FALLTHROUGH*/ 92155373Smjacob case CT_RESET: 92255373Smjacob if (fmsg == NULL) 92355373Smjacob fmsg = "Bus Reset"; 92455373Smjacob /*FALLTHROUGH*/ 92555373Smjacob case CT_ABORTED: 92655373Smjacob /* 92755373Smjacob * When an Abort message is received the firmware goes to 92855373Smjacob * Bus Free and returns all outstanding CTIOs with the status 92955373Smjacob * set, then sends us an Immediate Notify entry. 93055373Smjacob */ 93155373Smjacob if (fmsg == NULL) 93283027Smjacob fmsg = "ABORT TAG message sent by Initiator"; 93355373Smjacob 93464090Smjacob isp_prt(isp, ISP_LOGWARN, "CTIO destroyed by %s", fmsg); 93555373Smjacob break; 93655373Smjacob 93755373Smjacob case CT_INVAL: 93855373Smjacob /* 93955373Smjacob * CTIO rejected by the firmware due to disabled lun. 94055373Smjacob * "Cannot Happen". 94155373Smjacob */ 94264090Smjacob isp_prt(isp, ISP_LOGERR, 94364090Smjacob "Firmware rejected CTIO for disabled lun %d", 94464090Smjacob ct->ct_lun); 94555373Smjacob break; 94655373Smjacob 94755373Smjacob case CT_NOPATH: 94855373Smjacob /* 94955373Smjacob * CTIO rejected by the firmware due "no path for the 95055373Smjacob * nondisconnecting nexus specified". This means that 95155373Smjacob * we tried to access the bus while a non-disconnecting 95255373Smjacob * command is in process. 95355373Smjacob */ 95464090Smjacob isp_prt(isp, ISP_LOGERR, 95564090Smjacob "Firmware rejected CTIO for bad nexus %d/%d/%d", 95664090Smjacob ct->ct_iid, ct->ct_tgt, ct->ct_lun); 95755373Smjacob break; 95855373Smjacob 95955373Smjacob case CT_RSELTMO: 96055373Smjacob fmsg = "Reselection"; 96155373Smjacob /*FALLTHROUGH*/ 96255373Smjacob case CT_TIMEOUT: 96355373Smjacob if (fmsg == NULL) 96455373Smjacob fmsg = "Command"; 96564090Smjacob isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg); 96655373Smjacob break; 96755373Smjacob 96875196Smjacob case CT_PANIC: 96975196Smjacob if (fmsg == NULL) 97075196Smjacob fmsg = "Unrecoverable Error"; 97175196Smjacob /*FALLTHROUGH*/ 97255373Smjacob case CT_ERR: 97375196Smjacob if (fmsg == NULL) 97475196Smjacob fmsg = "Completed with Error"; 97555373Smjacob /*FALLTHROUGH*/ 97655373Smjacob case CT_PHASE_ERROR: 97755373Smjacob if (fmsg == NULL) 97855373Smjacob fmsg = "Phase Sequence Error"; 97955373Smjacob /*FALLTHROUGH*/ 98055373Smjacob case CT_TERMINATED: 98155373Smjacob if (fmsg == NULL) 98255373Smjacob fmsg = "terminated by TERMINATE TRANSFER"; 98355373Smjacob /*FALLTHROUGH*/ 98455373Smjacob case CT_NOACK: 98555373Smjacob if (fmsg == NULL) 98655373Smjacob fmsg = "unacknowledged Immediate Notify pending"; 98764090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg); 98855373Smjacob break; 98955373Smjacob default: 99064090Smjacob isp_prt(isp, ISP_LOGERR, "Unknown CTIO status 0x%x", 99155373Smjacob ct->ct_status & ~QLTM_SVALID); 99255373Smjacob break; 99355373Smjacob } 99455373Smjacob 99555373Smjacob if (xs == NULL) { 99655373Smjacob /* 99755373Smjacob * There may be more than one CTIO for a data transfer, 99855373Smjacob * or this may be a status CTIO we're not monitoring. 99955373Smjacob * 100055373Smjacob * The assumption is that they'll all be returned in the 100155373Smjacob * order we got them. 100255373Smjacob */ 100374232Smjacob if (ct->ct_syshandle == 0) { 100455373Smjacob if ((ct->ct_flags & CT_SENDSTATUS) == 0) { 100564090Smjacob isp_prt(isp, pl, 100664090Smjacob "intermediate CTIO completed ok"); 100755373Smjacob } else { 100864090Smjacob isp_prt(isp, pl, 100964090Smjacob "unmonitored CTIO completed ok"); 101055373Smjacob } 101155373Smjacob } else { 101264090Smjacob isp_prt(isp, pl, 101364090Smjacob "NO xs for CTIO (handle 0x%x) status 0x%x", 101474232Smjacob ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); 101555373Smjacob } 101655373Smjacob } else { 101777365Smjacob /* 101877365Smjacob * Final CTIO completed. Release DMA resources and 101977365Smjacob * notify platform dependent layers. 102077365Smjacob */ 102177365Smjacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 102274232Smjacob ISP_DMAFREE(isp, xs, ct->ct_syshandle); 102355373Smjacob } 102475196Smjacob isp_prt(isp, pl, "final CTIO complete"); 102555373Smjacob /* 102655373Smjacob * The platform layer will destroy the handle if appropriate. 102755373Smjacob */ 102875196Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct); 102955373Smjacob } 103055373Smjacob} 103155373Smjacob 103255373Smjacobstatic void 103375196Smjacobisp_handle_ctio2(struct ispsoftc *isp, ct2_entry_t *ct) 103455373Smjacob{ 103564090Smjacob XS_T *xs; 103664090Smjacob int pl = ISP_LOGTDEBUG2; 103755373Smjacob char *fmsg = NULL; 103855373Smjacob 103974232Smjacob if (ct->ct_syshandle) { 104074232Smjacob xs = isp_find_xs(isp, ct->ct_syshandle); 104155373Smjacob if (xs == NULL) 104264090Smjacob pl = ISP_LOGALL; 104355373Smjacob } else { 104455373Smjacob xs = NULL; 104555373Smjacob } 104655373Smjacob 104755373Smjacob switch(ct->ct_status & ~QLTM_SVALID) { 104877365Smjacob case CT_BUS_ERROR: 104977365Smjacob isp_prt(isp, ISP_LOGERR, "PCI DMA Bus Error"); 105077365Smjacob /* FALL Through */ 105177365Smjacob case CT_DATA_OVER: 105277365Smjacob case CT_DATA_UNDER: 105355373Smjacob case CT_OK: 105455373Smjacob /* 105555373Smjacob * There are generally 2 possibilities as to why we'd get 105655373Smjacob * this condition: 105755373Smjacob * We sent or received data. 105855373Smjacob * We sent status & command complete. 105955373Smjacob */ 106055373Smjacob 106155373Smjacob break; 106255373Smjacob 106355373Smjacob case CT_BDR_MSG: 106455373Smjacob /* 106577365Smjacob * Target Reset function received. 106655373Smjacob * 106755373Smjacob * The firmware generates an async mailbox interupt to 106855373Smjacob * notify us of this and returns outstanding CTIOs with this 106955373Smjacob * status. These CTIOs are handled in that same way as 107055373Smjacob * CT_ABORTED ones, so just fall through here. 107155373Smjacob */ 107277365Smjacob fmsg = "TARGET RESET Task Management Function Received"; 107355373Smjacob /*FALLTHROUGH*/ 107455373Smjacob case CT_RESET: 107555373Smjacob if (fmsg == NULL) 107677365Smjacob fmsg = "LIP Reset"; 107755373Smjacob /*FALLTHROUGH*/ 107855373Smjacob case CT_ABORTED: 107955373Smjacob /* 108055373Smjacob * When an Abort message is received the firmware goes to 108155373Smjacob * Bus Free and returns all outstanding CTIOs with the status 108255373Smjacob * set, then sends us an Immediate Notify entry. 108355373Smjacob */ 108455373Smjacob if (fmsg == NULL) 108577365Smjacob fmsg = "ABORT Task Management Function Received"; 108655373Smjacob 108764090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO2 destroyed by %s", fmsg); 108855373Smjacob break; 108955373Smjacob 109055373Smjacob case CT_INVAL: 109155373Smjacob /* 109256006Smjacob * CTIO rejected by the firmware - invalid data direction. 109355373Smjacob */ 109464090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO2 had wrong data directiond"); 109555373Smjacob break; 109655373Smjacob 109755373Smjacob case CT_RSELTMO: 109877365Smjacob fmsg = "failure to reconnect to initiator"; 109955373Smjacob /*FALLTHROUGH*/ 110055373Smjacob case CT_TIMEOUT: 110155373Smjacob if (fmsg == NULL) 110277365Smjacob fmsg = "command"; 110364090Smjacob isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg); 110455373Smjacob break; 110555373Smjacob 110655373Smjacob case CT_ERR: 110755373Smjacob fmsg = "Completed with Error"; 110855373Smjacob /*FALLTHROUGH*/ 110955373Smjacob case CT_LOGOUT: 111055373Smjacob if (fmsg == NULL) 111155373Smjacob fmsg = "Port Logout"; 111255373Smjacob /*FALLTHROUGH*/ 111355373Smjacob case CT_PORTNOTAVAIL: 111455373Smjacob if (fmsg == NULL) 111555373Smjacob fmsg = "Port not available"; 1116115521Sphk /*FALLTHROUGH*/ 111777365Smjacob case CT_PORTCHANGED: 111877365Smjacob if (fmsg == NULL) 111977365Smjacob fmsg = "Port Changed"; 1120115521Sphk /*FALLTHROUGH*/ 112155373Smjacob case CT_NOACK: 112255373Smjacob if (fmsg == NULL) 112355373Smjacob fmsg = "unacknowledged Immediate Notify pending"; 112464090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg); 112555373Smjacob break; 112655373Smjacob 112755373Smjacob case CT_INVRXID: 112855373Smjacob /* 112955373Smjacob * CTIO rejected by the firmware because an invalid RX_ID. 113055373Smjacob * Just print a message. 113155373Smjacob */ 113264090Smjacob isp_prt(isp, ISP_LOGERR, 113364090Smjacob "CTIO2 completed with Invalid RX_ID 0x%x", ct->ct_rxid); 113455373Smjacob break; 113555373Smjacob 113655373Smjacob default: 113775196Smjacob isp_prt(isp, ISP_LOGERR, "Unknown CTIO2 status 0x%x", 113864090Smjacob ct->ct_status & ~QLTM_SVALID); 113955373Smjacob break; 114055373Smjacob } 114155373Smjacob 114255373Smjacob if (xs == NULL) { 114355373Smjacob /* 114455373Smjacob * There may be more than one CTIO for a data transfer, 114555373Smjacob * or this may be a status CTIO we're not monitoring. 114655373Smjacob * 114755373Smjacob * The assumption is that they'll all be returned in the 114855373Smjacob * order we got them. 114955373Smjacob */ 115074232Smjacob if (ct->ct_syshandle == 0) { 115155373Smjacob if ((ct->ct_flags & CT_SENDSTATUS) == 0) { 115264090Smjacob isp_prt(isp, pl, 115364090Smjacob "intermediate CTIO completed ok"); 115455373Smjacob } else { 115564090Smjacob isp_prt(isp, pl, 115664090Smjacob "unmonitored CTIO completed ok"); 115755373Smjacob } 115855373Smjacob } else { 115964090Smjacob isp_prt(isp, pl, 116064090Smjacob "NO xs for CTIO (handle 0x%x) status 0x%x", 116174232Smjacob ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); 116255373Smjacob } 116355373Smjacob } else { 116477365Smjacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 116577365Smjacob ISP_DMAFREE(isp, xs, ct->ct_syshandle); 116677365Smjacob } 116755373Smjacob if (ct->ct_flags & CT_SENDSTATUS) { 116855373Smjacob /* 116955373Smjacob * Sent status and command complete. 117055373Smjacob * 117155373Smjacob * We're now really done with this command, so we 117255373Smjacob * punt to the platform dependent layers because 117355373Smjacob * only there can we do the appropriate command 117455373Smjacob * complete thread synchronization. 117555373Smjacob */ 117664090Smjacob isp_prt(isp, pl, "status CTIO complete"); 117755373Smjacob } else { 117855373Smjacob /* 117955373Smjacob * Final CTIO completed. Release DMA resources and 118055373Smjacob * notify platform dependent layers. 118155373Smjacob */ 118264090Smjacob isp_prt(isp, pl, "data CTIO complete"); 118355373Smjacob } 118455373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct); 118555373Smjacob /* 118655373Smjacob * The platform layer will destroy the handle if appropriate. 118755373Smjacob */ 118855373Smjacob } 118955373Smjacob} 119055373Smjacob#endif 1191