isp_target.c revision 120016
155373Smjacob/* $FreeBSD: head/sys/dev/isp/isp_target.c 120016 2003-09-13 01:58:26Z mjacob $ */ 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 366120016Smjacob 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; 542120016Smjacob case ASYNC_CTIO_DONE: 543120016Smjacob evt.ev_bus = bus; 544120016Smjacob evt.ev_event = event; 545120016Smjacob (void) isp_async(isp, ISPASYNC_TARGET_EVENT, &evt); 546120016Smjacob return (0); 54755373Smjacob default: 54864090Smjacob isp_prt(isp, ISP_LOGERR, 54964090Smjacob "isp_target_async: unknown event 0x%x", event); 55055373Smjacob break; 55155373Smjacob } 55263388Smjacob if (isp->isp_state == ISP_RUNSTATE) 55363388Smjacob isp_notify_ack(isp, NULL); 55498284Smjacob return(0); 55555373Smjacob} 55655373Smjacob 55755373Smjacob 55855373Smjacob/* 55955373Smjacob * Process a received message. 56055373Smjacob * The ISP firmware can handle most messages, there are only 56155373Smjacob * a few that we need to deal with: 56255373Smjacob * - abort: clean up the current command 56355373Smjacob * - abort tag and clear queue 56455373Smjacob */ 56555373Smjacob 56655373Smjacobstatic void 56775196Smjacobisp_got_msg(struct ispsoftc *isp, int bus, in_entry_t *inp) 56855373Smjacob{ 56955373Smjacob u_int8_t status = inp->in_status & ~QLTM_SVALID; 57055373Smjacob 57155373Smjacob if (status == IN_IDE_RECEIVED || status == IN_MSG_RECEIVED) { 57255373Smjacob tmd_msg_t msg; 57355373Smjacob 57455373Smjacob MEMZERO(&msg, sizeof (msg)); 57555373Smjacob msg.nt_bus = bus; 57655373Smjacob msg.nt_iid = inp->in_iid; 57755373Smjacob msg.nt_tgt = inp->in_tgt; 57855373Smjacob msg.nt_lun = inp->in_lun; 57955373Smjacob msg.nt_tagtype = inp->in_tag_type; 58055373Smjacob msg.nt_tagval = inp->in_tag_val; 58155373Smjacob MEMCPY(msg.nt_msg, inp->in_msg, IN_MSGLEN); 58255373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg); 58355373Smjacob } else { 58464090Smjacob isp_prt(isp, ISP_LOGERR, 58564090Smjacob "unknown immediate notify status 0x%x", inp->in_status); 58655373Smjacob } 58755373Smjacob} 58855373Smjacob 58955373Smjacob/* 59055373Smjacob * Synthesize a message from the task management flags in a FCP_CMND_IU. 59155373Smjacob */ 59255373Smjacobstatic void 59375196Smjacobisp_got_msg_fc(struct ispsoftc *isp, int bus, in_fcentry_t *inp) 59455373Smjacob{ 59582843Smjacob int lun; 59675196Smjacob static const char f1[] = "%s from iid %d lun %d seq 0x%x"; 59775196Smjacob static const char f2[] = 59864090Smjacob "unknown %s 0x%x lun %d iid %d task flags 0x%x seq 0x%x\n"; 59955373Smjacob 60082843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 60182843Smjacob lun = inp->in_scclun; 60282843Smjacob } else { 60382843Smjacob lun = inp->in_lun; 60482843Smjacob } 60582843Smjacob 60655373Smjacob if (inp->in_status != IN_MSG_RECEIVED) { 60764090Smjacob isp_prt(isp, ISP_LOGINFO, f2, "immediate notify status", 60882843Smjacob inp->in_status, lun, inp->in_iid, 60955373Smjacob inp->in_task_flags, inp->in_seqid); 61055373Smjacob } else { 61155373Smjacob tmd_msg_t msg; 61255373Smjacob 61355373Smjacob MEMZERO(&msg, sizeof (msg)); 61455373Smjacob msg.nt_bus = bus; 61555373Smjacob msg.nt_iid = inp->in_iid; 61655373Smjacob msg.nt_tagval = inp->in_seqid; 61782843Smjacob msg.nt_lun = lun; 61855373Smjacob 619120016Smjacob if (inp->in_task_flags & TASK_FLAGS_ABORT_TASK_SET) { 620120016Smjacob isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK SET", 621105134Smjacob inp->in_iid, lun, inp->in_seqid); 622120016Smjacob msg.nt_msg[0] = MSG_ABORT; 62355373Smjacob } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_TASK_SET) { 62464090Smjacob isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET", 625105134Smjacob inp->in_iid, lun, inp->in_seqid); 62655373Smjacob msg.nt_msg[0] = MSG_CLEAR_QUEUE; 627120016Smjacob } else if (inp->in_task_flags & TASK_FLAGS_LUN_RESET) { 628120016Smjacob isp_prt(isp, ISP_LOGINFO, f1, "LUN RESET", 629120016Smjacob inp->in_iid, lun, inp->in_seqid); 630120016Smjacob msg.nt_msg[0] = MSG_LUN_RESET; 63155373Smjacob } else if (inp->in_task_flags & TASK_FLAGS_TARGET_RESET) { 63264090Smjacob isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET", 633105134Smjacob inp->in_iid, lun, inp->in_seqid); 63455373Smjacob msg.nt_msg[0] = MSG_BUS_DEV_RESET; 63555373Smjacob } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_ACA) { 63664090Smjacob isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA", 637105134Smjacob inp->in_iid, lun, inp->in_seqid); 63855373Smjacob msg.nt_msg[0] = MSG_REL_RECOVERY; 63955373Smjacob } else { 64064090Smjacob isp_prt(isp, ISP_LOGWARN, f2, "task flag", 641105134Smjacob inp->in_status, lun, inp->in_iid, 64255373Smjacob inp->in_task_flags, inp->in_seqid); 64355373Smjacob } 64455373Smjacob if (msg.nt_msg[0]) { 64555373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_MESSAGE, &msg); 64655373Smjacob } 64755373Smjacob } 64855373Smjacob} 64955373Smjacob 65055373Smjacobstatic void 65175196Smjacobisp_notify_ack(struct ispsoftc *isp, void *arg) 65255373Smjacob{ 65355373Smjacob char storage[QENTRY_LEN]; 65487635Smjacob u_int16_t nxti, optr; 65555373Smjacob void *outp; 65655373Smjacob 65787635Smjacob if (isp_getrqentry(isp, &nxti, &optr, &outp)) { 65864090Smjacob isp_prt(isp, ISP_LOGWARN, 65964090Smjacob "Request Queue Overflow For isp_notify_ack"); 66055373Smjacob return; 66155373Smjacob } 66255373Smjacob 66356006Smjacob MEMZERO(storage, QENTRY_LEN); 66455373Smjacob 66555373Smjacob if (IS_FC(isp)) { 66655373Smjacob na_fcentry_t *na = (na_fcentry_t *) storage; 66755373Smjacob if (arg) { 66855373Smjacob in_fcentry_t *inp = arg; 66956006Smjacob MEMCPY(storage, arg, sizeof (isphdr_t)); 67055373Smjacob na->na_iid = inp->in_iid; 67182843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 67261774Smjacob na->na_lun = inp->in_scclun; 67361774Smjacob } else { 67461774Smjacob na->na_lun = inp->in_lun; 67561774Smjacob } 67655373Smjacob na->na_task_flags = inp->in_task_flags; 67755373Smjacob na->na_seqid = inp->in_seqid; 67855373Smjacob na->na_flags = NAFC_RCOUNT; 67990224Smjacob na->na_status = inp->in_status; 68055373Smjacob if (inp->in_status == IN_RESET) { 68155373Smjacob na->na_flags |= NAFC_RST_CLRD; 68255373Smjacob } 68355373Smjacob } else { 68455373Smjacob na->na_flags = NAFC_RST_CLRD; 68555373Smjacob } 68659453Smjacob na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; 68759453Smjacob na->na_header.rqs_entry_count = 1; 68887635Smjacob isp_put_notify_ack_fc(isp, na, (na_fcentry_t *)outp); 68955373Smjacob } else { 69055373Smjacob na_entry_t *na = (na_entry_t *) storage; 69155373Smjacob if (arg) { 69255373Smjacob in_entry_t *inp = arg; 69356006Smjacob MEMCPY(storage, arg, sizeof (isphdr_t)); 69455373Smjacob na->na_iid = inp->in_iid; 69555373Smjacob na->na_lun = inp->in_lun; 69655373Smjacob na->na_tgt = inp->in_tgt; 69755373Smjacob na->na_seqid = inp->in_seqid; 69855373Smjacob if (inp->in_status == IN_RESET) { 69959453Smjacob na->na_event = NA_RST_CLRD; 70055373Smjacob } 70155373Smjacob } else { 70259453Smjacob na->na_event = NA_RST_CLRD; 70355373Smjacob } 70459453Smjacob na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; 70559453Smjacob na->na_header.rqs_entry_count = 1; 70687635Smjacob isp_put_notify_ack(isp, na, (na_entry_t *)outp); 70755373Smjacob } 70855373Smjacob ISP_TDQE(isp, "isp_notify_ack", (int) optr, storage); 70987635Smjacob ISP_ADD_REQUEST(isp, nxti); 71055373Smjacob} 71155373Smjacob 71255373Smjacobstatic void 71375196Smjacobisp_handle_atio(struct ispsoftc *isp, at_entry_t *aep) 71455373Smjacob{ 71555373Smjacob int lun; 71655373Smjacob lun = aep->at_lun; 71755373Smjacob /* 71855373Smjacob * The firmware status (except for the QLTM_SVALID bit) indicates 71955373Smjacob * why this ATIO was sent to us. 72055373Smjacob * 72155373Smjacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 72255373Smjacob * 72355373Smjacob * If the DISCONNECTS DISABLED bit is set in the flags field, 72455373Smjacob * we're still connected on the SCSI bus - i.e. the initiator 72555373Smjacob * did not set DiscPriv in the identify message. We don't care 72655373Smjacob * about this so it's ignored. 72755373Smjacob */ 72855373Smjacob 72955373Smjacob switch(aep->at_status & ~QLTM_SVALID) { 73055373Smjacob case AT_PATH_INVALID: 73155373Smjacob /* 73255373Smjacob * ATIO rejected by the firmware due to disabled lun. 73355373Smjacob */ 73464090Smjacob isp_prt(isp, ISP_LOGERR, 73564090Smjacob "rejected ATIO for disabled lun %d", lun); 73655373Smjacob break; 73755373Smjacob case AT_NOCAP: 73855373Smjacob /* 73955373Smjacob * Requested Capability not available 74055373Smjacob * We sent an ATIO that overflowed the firmware's 74155373Smjacob * command resource count. 74255373Smjacob */ 74364090Smjacob isp_prt(isp, ISP_LOGERR, 74464090Smjacob "rejected ATIO for lun %d because of command count" 74564090Smjacob " overflow", lun); 74655373Smjacob break; 74755373Smjacob 74855373Smjacob case AT_BDR_MSG: 74955373Smjacob /* 75055373Smjacob * If we send an ATIO to the firmware to increment 75155373Smjacob * its command resource count, and the firmware is 75255373Smjacob * recovering from a Bus Device Reset, it returns 75355373Smjacob * the ATIO with this status. We set the command 75487635Smjacob * resource count in the Enable Lun entry and do 75555373Smjacob * not increment it. Therefore we should never get 75655373Smjacob * this status here. 75755373Smjacob */ 75883027Smjacob isp_prt(isp, ISP_LOGERR, atiocope, lun, 75983027Smjacob GET_BUS_VAL(aep->at_iid)); 76055373Smjacob break; 76155373Smjacob 76255373Smjacob case AT_CDB: /* Got a CDB */ 76355373Smjacob case AT_PHASE_ERROR: /* Bus Phase Sequence Error */ 76455373Smjacob /* 76555373Smjacob * Punt to platform specific layer. 76655373Smjacob */ 76755373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep); 76855373Smjacob break; 76955373Smjacob 77055373Smjacob case AT_RESET: 77155373Smjacob /* 772108470Sschweikh * A bus reset came along and blew away this command. Why 77355373Smjacob * they do this in addition the async event code stuff, 77455373Smjacob * I dunno. 77555373Smjacob * 77655373Smjacob * Ignore it because the async event will clear things 77755373Smjacob * up for us. 77855373Smjacob */ 77983027Smjacob isp_prt(isp, ISP_LOGWARN, atior, lun, 78083027Smjacob GET_IID_VAL(aep->at_iid), GET_BUS_VAL(aep->at_iid)); 78155373Smjacob break; 78255373Smjacob 78355373Smjacob 78455373Smjacob default: 78564090Smjacob isp_prt(isp, ISP_LOGERR, 78664090Smjacob "Unknown ATIO status 0x%x from initiator %d for lun %d", 78764090Smjacob aep->at_status, aep->at_iid, lun); 78875196Smjacob (void) isp_target_put_atio(isp, aep); 78955373Smjacob break; 79055373Smjacob } 79155373Smjacob} 79255373Smjacob 79355373Smjacobstatic void 79475196Smjacobisp_handle_atio2(struct ispsoftc *isp, at2_entry_t *aep) 79555373Smjacob{ 79655373Smjacob int lun; 79761774Smjacob 79882843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 79961774Smjacob lun = aep->at_scclun; 80061774Smjacob } else { 80161774Smjacob lun = aep->at_lun; 80261774Smjacob } 80361774Smjacob 80455373Smjacob /* 80555373Smjacob * The firmware status (except for the QLTM_SVALID bit) indicates 80655373Smjacob * why this ATIO was sent to us. 80755373Smjacob * 80855373Smjacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 80955373Smjacob * 81055373Smjacob * If the DISCONNECTS DISABLED bit is set in the flags field, 81155373Smjacob * we're still connected on the SCSI bus - i.e. the initiator 81255373Smjacob * did not set DiscPriv in the identify message. We don't care 81355373Smjacob * about this so it's ignored. 81455373Smjacob */ 81555373Smjacob 81655373Smjacob switch(aep->at_status & ~QLTM_SVALID) { 81755373Smjacob case AT_PATH_INVALID: 81855373Smjacob /* 81955373Smjacob * ATIO rejected by the firmware due to disabled lun. 82055373Smjacob */ 82164090Smjacob isp_prt(isp, ISP_LOGERR, 82264090Smjacob "rejected ATIO2 for disabled lun %d", lun); 82355373Smjacob break; 82455373Smjacob case AT_NOCAP: 82555373Smjacob /* 82655373Smjacob * Requested Capability not available 82755373Smjacob * We sent an ATIO that overflowed the firmware's 82855373Smjacob * command resource count. 82955373Smjacob */ 83064090Smjacob isp_prt(isp, ISP_LOGERR, 83164090Smjacob "rejected ATIO2 for lun %d- command count overflow", lun); 83255373Smjacob break; 83355373Smjacob 83455373Smjacob case AT_BDR_MSG: 83555373Smjacob /* 83655373Smjacob * If we send an ATIO to the firmware to increment 83755373Smjacob * its command resource count, and the firmware is 83855373Smjacob * recovering from a Bus Device Reset, it returns 83955373Smjacob * the ATIO with this status. We set the command 84055373Smjacob * resource count in the Enable Lun entry and no 84155373Smjacob * not increment it. Therefore we should never get 84255373Smjacob * this status here. 84355373Smjacob */ 84483027Smjacob isp_prt(isp, ISP_LOGERR, atiocope, lun, 0); 84555373Smjacob break; 84655373Smjacob 84755373Smjacob case AT_CDB: /* Got a CDB */ 84855373Smjacob /* 84955373Smjacob * Punt to platform specific layer. 85055373Smjacob */ 85155373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep); 85255373Smjacob break; 85355373Smjacob 85455373Smjacob case AT_RESET: 85555373Smjacob /* 85655373Smjacob * A bus reset came along an blew away this command. Why 85755373Smjacob * they do this in addition the async event code stuff, 85855373Smjacob * I dunno. 85955373Smjacob * 86055373Smjacob * Ignore it because the async event will clear things 86155373Smjacob * up for us. 86255373Smjacob */ 86383027Smjacob isp_prt(isp, ISP_LOGERR, atior, lun, aep->at_iid, 0); 86455373Smjacob break; 86555373Smjacob 86655373Smjacob 86755373Smjacob default: 86864090Smjacob isp_prt(isp, ISP_LOGERR, 86964090Smjacob "Unknown ATIO2 status 0x%x from initiator %d for lun %d", 87064090Smjacob aep->at_status, aep->at_iid, lun); 87175196Smjacob (void) isp_target_put_atio(isp, aep); 87255373Smjacob break; 87355373Smjacob } 87455373Smjacob} 87555373Smjacob 87655373Smjacobstatic void 87775196Smjacobisp_handle_ctio(struct ispsoftc *isp, ct_entry_t *ct) 87855373Smjacob{ 87974232Smjacob void *xs; 88064090Smjacob int pl = ISP_LOGTDEBUG2; 88155373Smjacob char *fmsg = NULL; 88255373Smjacob 88374232Smjacob if (ct->ct_syshandle) { 88474232Smjacob xs = isp_find_xs(isp, ct->ct_syshandle); 88555373Smjacob if (xs == NULL) 88664090Smjacob pl = ISP_LOGALL; 88755373Smjacob } else { 88855373Smjacob xs = NULL; 88955373Smjacob } 89055373Smjacob 89155373Smjacob switch(ct->ct_status & ~QLTM_SVALID) { 89255373Smjacob case CT_OK: 89355373Smjacob /* 89455373Smjacob * There are generally 3 possibilities as to why we'd get 89555373Smjacob * this condition: 89655373Smjacob * We disconnected after receiving a CDB. 89755373Smjacob * We sent or received data. 89855373Smjacob * We sent status & command complete. 89955373Smjacob */ 90055373Smjacob 90159453Smjacob if (ct->ct_flags & CT_SENDSTATUS) { 90259453Smjacob break; 90359453Smjacob } else if ((ct->ct_flags & CT_DATAMASK) == CT_NO_DATA) { 90455373Smjacob /* 90555373Smjacob * Nothing to do in this case. 90655373Smjacob */ 90764090Smjacob isp_prt(isp, pl, "CTIO- iid %d disconnected OK", 90864090Smjacob ct->ct_iid); 90955373Smjacob return; 91055373Smjacob } 91155373Smjacob break; 91255373Smjacob 91355373Smjacob case CT_BDR_MSG: 91455373Smjacob /* 91555373Smjacob * Bus Device Reset message received or the SCSI Bus has 91655373Smjacob * been Reset; the firmware has gone to Bus Free. 91755373Smjacob * 91855373Smjacob * The firmware generates an async mailbox interupt to 91955373Smjacob * notify us of this and returns outstanding CTIOs with this 92055373Smjacob * status. These CTIOs are handled in that same way as 92155373Smjacob * CT_ABORTED ones, so just fall through here. 92255373Smjacob */ 92355373Smjacob fmsg = "Bus Device Reset"; 92455373Smjacob /*FALLTHROUGH*/ 92555373Smjacob case CT_RESET: 92655373Smjacob if (fmsg == NULL) 92755373Smjacob fmsg = "Bus Reset"; 92855373Smjacob /*FALLTHROUGH*/ 92955373Smjacob case CT_ABORTED: 93055373Smjacob /* 93155373Smjacob * When an Abort message is received the firmware goes to 93255373Smjacob * Bus Free and returns all outstanding CTIOs with the status 93355373Smjacob * set, then sends us an Immediate Notify entry. 93455373Smjacob */ 93555373Smjacob if (fmsg == NULL) 93683027Smjacob fmsg = "ABORT TAG message sent by Initiator"; 93755373Smjacob 93864090Smjacob isp_prt(isp, ISP_LOGWARN, "CTIO destroyed by %s", fmsg); 93955373Smjacob break; 94055373Smjacob 94155373Smjacob case CT_INVAL: 94255373Smjacob /* 94355373Smjacob * CTIO rejected by the firmware due to disabled lun. 94455373Smjacob * "Cannot Happen". 94555373Smjacob */ 94664090Smjacob isp_prt(isp, ISP_LOGERR, 94764090Smjacob "Firmware rejected CTIO for disabled lun %d", 94864090Smjacob ct->ct_lun); 94955373Smjacob break; 95055373Smjacob 95155373Smjacob case CT_NOPATH: 95255373Smjacob /* 95355373Smjacob * CTIO rejected by the firmware due "no path for the 95455373Smjacob * nondisconnecting nexus specified". This means that 95555373Smjacob * we tried to access the bus while a non-disconnecting 95655373Smjacob * command is in process. 95755373Smjacob */ 95864090Smjacob isp_prt(isp, ISP_LOGERR, 95964090Smjacob "Firmware rejected CTIO for bad nexus %d/%d/%d", 96064090Smjacob ct->ct_iid, ct->ct_tgt, ct->ct_lun); 96155373Smjacob break; 96255373Smjacob 96355373Smjacob case CT_RSELTMO: 96455373Smjacob fmsg = "Reselection"; 96555373Smjacob /*FALLTHROUGH*/ 96655373Smjacob case CT_TIMEOUT: 96755373Smjacob if (fmsg == NULL) 96855373Smjacob fmsg = "Command"; 96964090Smjacob isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg); 97055373Smjacob break; 97155373Smjacob 97275196Smjacob case CT_PANIC: 97375196Smjacob if (fmsg == NULL) 97475196Smjacob fmsg = "Unrecoverable Error"; 97575196Smjacob /*FALLTHROUGH*/ 97655373Smjacob case CT_ERR: 97775196Smjacob if (fmsg == NULL) 97875196Smjacob fmsg = "Completed with Error"; 97955373Smjacob /*FALLTHROUGH*/ 98055373Smjacob case CT_PHASE_ERROR: 98155373Smjacob if (fmsg == NULL) 98255373Smjacob fmsg = "Phase Sequence Error"; 98355373Smjacob /*FALLTHROUGH*/ 98455373Smjacob case CT_TERMINATED: 98555373Smjacob if (fmsg == NULL) 98655373Smjacob fmsg = "terminated by TERMINATE TRANSFER"; 98755373Smjacob /*FALLTHROUGH*/ 98855373Smjacob case CT_NOACK: 98955373Smjacob if (fmsg == NULL) 99055373Smjacob fmsg = "unacknowledged Immediate Notify pending"; 99164090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg); 99255373Smjacob break; 99355373Smjacob default: 99464090Smjacob isp_prt(isp, ISP_LOGERR, "Unknown CTIO status 0x%x", 99555373Smjacob ct->ct_status & ~QLTM_SVALID); 99655373Smjacob break; 99755373Smjacob } 99855373Smjacob 99955373Smjacob if (xs == NULL) { 100055373Smjacob /* 100155373Smjacob * There may be more than one CTIO for a data transfer, 100255373Smjacob * or this may be a status CTIO we're not monitoring. 100355373Smjacob * 100455373Smjacob * The assumption is that they'll all be returned in the 100555373Smjacob * order we got them. 100655373Smjacob */ 100774232Smjacob if (ct->ct_syshandle == 0) { 100855373Smjacob if ((ct->ct_flags & CT_SENDSTATUS) == 0) { 100964090Smjacob isp_prt(isp, pl, 101064090Smjacob "intermediate CTIO completed ok"); 101155373Smjacob } else { 101264090Smjacob isp_prt(isp, pl, 101364090Smjacob "unmonitored CTIO completed ok"); 101455373Smjacob } 101555373Smjacob } else { 101664090Smjacob isp_prt(isp, pl, 101764090Smjacob "NO xs for CTIO (handle 0x%x) status 0x%x", 101874232Smjacob ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); 101955373Smjacob } 102055373Smjacob } else { 102177365Smjacob /* 102277365Smjacob * Final CTIO completed. Release DMA resources and 102377365Smjacob * notify platform dependent layers. 102477365Smjacob */ 102577365Smjacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 102674232Smjacob ISP_DMAFREE(isp, xs, ct->ct_syshandle); 102755373Smjacob } 102875196Smjacob isp_prt(isp, pl, "final CTIO complete"); 102955373Smjacob /* 103055373Smjacob * The platform layer will destroy the handle if appropriate. 103155373Smjacob */ 103275196Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct); 103355373Smjacob } 103455373Smjacob} 103555373Smjacob 103655373Smjacobstatic void 103775196Smjacobisp_handle_ctio2(struct ispsoftc *isp, ct2_entry_t *ct) 103855373Smjacob{ 103964090Smjacob XS_T *xs; 104064090Smjacob int pl = ISP_LOGTDEBUG2; 104155373Smjacob char *fmsg = NULL; 104255373Smjacob 104374232Smjacob if (ct->ct_syshandle) { 104474232Smjacob xs = isp_find_xs(isp, ct->ct_syshandle); 104555373Smjacob if (xs == NULL) 104664090Smjacob pl = ISP_LOGALL; 104755373Smjacob } else { 104855373Smjacob xs = NULL; 104955373Smjacob } 105055373Smjacob 105155373Smjacob switch(ct->ct_status & ~QLTM_SVALID) { 105277365Smjacob case CT_BUS_ERROR: 105377365Smjacob isp_prt(isp, ISP_LOGERR, "PCI DMA Bus Error"); 105477365Smjacob /* FALL Through */ 105577365Smjacob case CT_DATA_OVER: 105677365Smjacob case CT_DATA_UNDER: 105755373Smjacob case CT_OK: 105855373Smjacob /* 105955373Smjacob * There are generally 2 possibilities as to why we'd get 106055373Smjacob * this condition: 106155373Smjacob * We sent or received data. 106255373Smjacob * We sent status & command complete. 106355373Smjacob */ 106455373Smjacob 106555373Smjacob break; 106655373Smjacob 106755373Smjacob case CT_BDR_MSG: 106855373Smjacob /* 106977365Smjacob * Target Reset function received. 107055373Smjacob * 107155373Smjacob * The firmware generates an async mailbox interupt to 107255373Smjacob * notify us of this and returns outstanding CTIOs with this 107355373Smjacob * status. These CTIOs are handled in that same way as 107455373Smjacob * CT_ABORTED ones, so just fall through here. 107555373Smjacob */ 107677365Smjacob fmsg = "TARGET RESET Task Management Function Received"; 107755373Smjacob /*FALLTHROUGH*/ 107855373Smjacob case CT_RESET: 107955373Smjacob if (fmsg == NULL) 108077365Smjacob fmsg = "LIP Reset"; 108155373Smjacob /*FALLTHROUGH*/ 108255373Smjacob case CT_ABORTED: 108355373Smjacob /* 108455373Smjacob * When an Abort message is received the firmware goes to 108555373Smjacob * Bus Free and returns all outstanding CTIOs with the status 108655373Smjacob * set, then sends us an Immediate Notify entry. 108755373Smjacob */ 108855373Smjacob if (fmsg == NULL) 108977365Smjacob fmsg = "ABORT Task Management Function Received"; 109055373Smjacob 109164090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO2 destroyed by %s", fmsg); 109255373Smjacob break; 109355373Smjacob 109455373Smjacob case CT_INVAL: 109555373Smjacob /* 109656006Smjacob * CTIO rejected by the firmware - invalid data direction. 109755373Smjacob */ 1098120016Smjacob isp_prt(isp, ISP_LOGERR, "CTIO2 had wrong data direction"); 109955373Smjacob break; 110055373Smjacob 110155373Smjacob case CT_RSELTMO: 110277365Smjacob fmsg = "failure to reconnect to initiator"; 110355373Smjacob /*FALLTHROUGH*/ 110455373Smjacob case CT_TIMEOUT: 110555373Smjacob if (fmsg == NULL) 110677365Smjacob fmsg = "command"; 110764090Smjacob isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg); 110855373Smjacob break; 110955373Smjacob 111055373Smjacob case CT_ERR: 111155373Smjacob fmsg = "Completed with Error"; 111255373Smjacob /*FALLTHROUGH*/ 111355373Smjacob case CT_LOGOUT: 111455373Smjacob if (fmsg == NULL) 111555373Smjacob fmsg = "Port Logout"; 111655373Smjacob /*FALLTHROUGH*/ 111755373Smjacob case CT_PORTNOTAVAIL: 111855373Smjacob if (fmsg == NULL) 111955373Smjacob fmsg = "Port not available"; 1120115521Sphk /*FALLTHROUGH*/ 112177365Smjacob case CT_PORTCHANGED: 112277365Smjacob if (fmsg == NULL) 112377365Smjacob fmsg = "Port Changed"; 1124115521Sphk /*FALLTHROUGH*/ 112555373Smjacob case CT_NOACK: 112655373Smjacob if (fmsg == NULL) 112755373Smjacob fmsg = "unacknowledged Immediate Notify pending"; 112864090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg); 112955373Smjacob break; 113055373Smjacob 113155373Smjacob case CT_INVRXID: 113255373Smjacob /* 113355373Smjacob * CTIO rejected by the firmware because an invalid RX_ID. 113455373Smjacob * Just print a message. 113555373Smjacob */ 113664090Smjacob isp_prt(isp, ISP_LOGERR, 113764090Smjacob "CTIO2 completed with Invalid RX_ID 0x%x", ct->ct_rxid); 113855373Smjacob break; 113955373Smjacob 114055373Smjacob default: 114175196Smjacob isp_prt(isp, ISP_LOGERR, "Unknown CTIO2 status 0x%x", 114264090Smjacob ct->ct_status & ~QLTM_SVALID); 114355373Smjacob break; 114455373Smjacob } 114555373Smjacob 114655373Smjacob if (xs == NULL) { 114755373Smjacob /* 114855373Smjacob * There may be more than one CTIO for a data transfer, 114955373Smjacob * or this may be a status CTIO we're not monitoring. 115055373Smjacob * 115155373Smjacob * The assumption is that they'll all be returned in the 115255373Smjacob * order we got them. 115355373Smjacob */ 115474232Smjacob if (ct->ct_syshandle == 0) { 115555373Smjacob if ((ct->ct_flags & CT_SENDSTATUS) == 0) { 115664090Smjacob isp_prt(isp, pl, 115764090Smjacob "intermediate CTIO completed ok"); 115855373Smjacob } else { 115964090Smjacob isp_prt(isp, pl, 116064090Smjacob "unmonitored CTIO completed ok"); 116155373Smjacob } 116255373Smjacob } else { 116364090Smjacob isp_prt(isp, pl, 116464090Smjacob "NO xs for CTIO (handle 0x%x) status 0x%x", 116574232Smjacob ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); 116655373Smjacob } 116755373Smjacob } else { 116877365Smjacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 116977365Smjacob ISP_DMAFREE(isp, xs, ct->ct_syshandle); 117077365Smjacob } 117155373Smjacob if (ct->ct_flags & CT_SENDSTATUS) { 117255373Smjacob /* 117355373Smjacob * Sent status and command complete. 117455373Smjacob * 117555373Smjacob * We're now really done with this command, so we 117655373Smjacob * punt to the platform dependent layers because 117755373Smjacob * only there can we do the appropriate command 117855373Smjacob * complete thread synchronization. 117955373Smjacob */ 118064090Smjacob isp_prt(isp, pl, "status CTIO complete"); 118155373Smjacob } else { 118255373Smjacob /* 118355373Smjacob * Final CTIO completed. Release DMA resources and 118455373Smjacob * notify platform dependent layers. 118555373Smjacob */ 118664090Smjacob isp_prt(isp, pl, "data CTIO complete"); 118755373Smjacob } 118855373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct); 118955373Smjacob /* 119055373Smjacob * The platform layer will destroy the handle if appropriate. 119155373Smjacob */ 119255373Smjacob } 119355373Smjacob} 119455373Smjacob#endif 1195