isp_target.c revision 154704
1139749Simp/*- 255373Smjacob * Machine and OS Independent Target Mode Code for the Qlogic SCSI/FC adapters. 355373Smjacob * 4154704Smjacob * Copyright (c) 1997-2006 by Matthew Jacob 555373Smjacob * All rights reserved. 655373Smjacob * 755373Smjacob * Redistribution and use in source and binary forms, with or without 855373Smjacob * modification, are permitted provided that the following conditions 955373Smjacob * are met: 1055373Smjacob * 1. Redistributions of source code must retain the above copyright 1155373Smjacob * notice immediately at the beginning of the file, without modification, 1255373Smjacob * this list of conditions, and the following disclaimer. 1366189Smjacob * 2. The name of the author may not be used to endorse or promote products 1455373Smjacob * derived from this software without specific prior written permission. 1555373Smjacob * 1655373Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1755373Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1855373Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1955373Smjacob * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2055373Smjacob * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2155373Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2255373Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2355373Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2455373Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2555373Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2655373Smjacob * SUCH DAMAGE. 2755373Smjacob */ 2855373Smjacob 2955373Smjacob/* 3090224Smjacob * Bug fixes gratefully acknowledged from: 3190224Smjacob * Oded Kedem <oded@kashya.com> 3290224Smjacob */ 3390224Smjacob/* 3455373Smjacob * Include header file appropriate for platform we're building on. 3555373Smjacob */ 3655373Smjacob 3755373Smjacob#ifdef __NetBSD__ 3855373Smjacob#include <dev/ic/isp_netbsd.h> 3955373Smjacob#endif 4055373Smjacob#ifdef __FreeBSD__ 41154704Smjacob#include <sys/cdefs.h> 42154704Smjacob__FBSDID("$FreeBSD: head/sys/dev/isp/isp_target.c 154704 2006-01-23 06:23:37Z mjacob $"); 43154704Smjacob 4455373Smjacob#include <dev/isp/isp_freebsd.h> 4555373Smjacob#endif 4655373Smjacob#ifdef __OpenBSD__ 4755373Smjacob#include <dev/ic/isp_openbsd.h> 4855373Smjacob#endif 4955373Smjacob#ifdef __linux__ 5055373Smjacob#include "isp_linux.h" 5155373Smjacob#endif 5255373Smjacob 5355373Smjacob#ifdef ISP_TARGET_MODE 5475196Smjacobstatic const char atiocope[] = 5583027Smjacob "ATIO returned for lun %d because it was in the middle of Bus Device Reset " 5683027Smjacob "on bus %d"; 5775196Smjacobstatic const char atior[] = 5883027Smjacob "ATIO returned on for lun %d on from IID %d because a Bus Reset occurred " 5983027Smjacob "on bus %d"; 6055373Smjacob 61154704Smjacobstatic void isp_got_msg(struct ispsoftc *, in_entry_t *); 62154704Smjacobstatic void isp_got_msg_fc(struct ispsoftc *, in_fcentry_t *); 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; 121154704Smjacob at2e_entry_t *at2eiop; 12255373Smjacob ct_entry_t *ctiop; 12355373Smjacob ct2_entry_t *ct2iop; 124154704Smjacob ct2e_entry_t *ct2eiop; 12555373Smjacob lun_entry_t *lunenp; 12655373Smjacob in_entry_t *inotp; 12755373Smjacob in_fcentry_t *inot_fcp; 128154704Smjacob in_fcentry_e_t *inote_fcp; 12955373Smjacob na_entry_t *nackp; 13055373Smjacob na_fcentry_t *nack_fcp; 131154704Smjacob na_fcentry_e_t *nacke_fcp; 13255373Smjacob isphdr_t *hp; 13355373Smjacob void * *vp; 13455373Smjacob#define atiop unp.atiop 13555373Smjacob#define at2iop unp.at2iop 136154704Smjacob#define at2eiop unp.at2eiop 13755373Smjacob#define ctiop unp.ctiop 13855373Smjacob#define ct2iop unp.ct2iop 139154704Smjacob#define ct2eiop unp.ct2eiop 14055373Smjacob#define lunenp unp.lunenp 14155373Smjacob#define inotp unp.inotp 14255373Smjacob#define inot_fcp unp.inot_fcp 143154704Smjacob#define inote_fcp unp.inote_fcp 14455373Smjacob#define nackp unp.nackp 14555373Smjacob#define nack_fcp unp.nack_fcp 146154704Smjacob#define nacke_fcp unp.nacke_fcp 14755373Smjacob#define hdrp unp.hp 14855373Smjacob } unp; 14987635Smjacob u_int8_t local[QENTRY_LEN]; 15098284Smjacob int bus, type, rval = 1; 15155373Smjacob 15287635Smjacob type = isp_get_response_type(isp, (isphdr_t *)vptr); 15355373Smjacob unp.vp = vptr; 15455373Smjacob 15555373Smjacob ISP_TDQE(isp, "isp_target_notify", (int) *optrp, vptr); 15655373Smjacob 15787635Smjacob switch(type) { 15855373Smjacob case RQSTYPE_ATIO: 15987635Smjacob isp_get_atio(isp, atiop, (at_entry_t *) local); 16087635Smjacob isp_handle_atio(isp, (at_entry_t *) local); 16155373Smjacob break; 16255373Smjacob case RQSTYPE_CTIO: 16387635Smjacob isp_get_ctio(isp, ctiop, (ct_entry_t *) local); 16487635Smjacob isp_handle_ctio(isp, (ct_entry_t *) local); 16555373Smjacob break; 16655373Smjacob case RQSTYPE_ATIO2: 167154704Smjacob if (IS_2KLOGIN(isp)) 168154704Smjacob isp_get_atio2e(isp, at2eiop, (at2e_entry_t *) local); 169154704Smjacob else 170154704Smjacob isp_get_atio2(isp, at2iop, (at2_entry_t *) local); 17187635Smjacob isp_handle_atio2(isp, (at2_entry_t *) local); 17255373Smjacob break; 173125187Smjacob case RQSTYPE_CTIO3: 17455373Smjacob case RQSTYPE_CTIO2: 175154704Smjacob if (IS_2KLOGIN(isp)) 176154704Smjacob isp_get_ctio2e(isp, ct2eiop, (ct2e_entry_t *) local); 177154704Smjacob else 178154704Smjacob isp_get_ctio2(isp, ct2iop, (ct2_entry_t *) local); 17987635Smjacob isp_handle_ctio2(isp, (ct2_entry_t *) local); 18055373Smjacob break; 18155373Smjacob case RQSTYPE_ENABLE_LUN: 18255373Smjacob case RQSTYPE_MODIFY_LUN: 18387635Smjacob isp_get_enable_lun(isp, lunenp, (lun_entry_t *) local); 18487635Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, local); 18555373Smjacob break; 18655373Smjacob 18755373Smjacob case RQSTYPE_NOTIFY: 18855373Smjacob /* 18955373Smjacob * Either the ISP received a SCSI message it can't 19055373Smjacob * handle, or it's returning an Immed. Notify entry 19155373Smjacob * we sent. We can send Immed. Notify entries to 19255373Smjacob * increment the firmware's resource count for them 19355373Smjacob * (we set this initially in the Enable Lun entry). 19455373Smjacob */ 19557216Smjacob bus = 0; 19655373Smjacob if (IS_FC(isp)) { 197154704Smjacob if (IS_2KLOGIN(isp)) 198154704Smjacob isp_get_notify_fc_e(isp, inote_fcp, (in_fcentry_e_t *)local); 199154704Smjacob isp_get_notify_fc(isp, inot_fcp, (in_fcentry_t *)local); 20087635Smjacob inot_fcp = (in_fcentry_t *) local; 20155373Smjacob status = inot_fcp->in_status; 20255373Smjacob seqid = inot_fcp->in_seqid; 20355373Smjacob } else { 20487635Smjacob isp_get_notify(isp, inotp, (in_entry_t *)local); 20587635Smjacob inotp = (in_entry_t *) local; 20655373Smjacob status = inotp->in_status & 0xff; 20755373Smjacob seqid = inotp->in_seqid; 20857216Smjacob if (IS_DUALBUS(isp)) { 20983027Smjacob bus = GET_BUS_VAL(inotp->in_iid); 21083027Smjacob SET_BUS_VAL(inotp->in_iid, 0); 21157216Smjacob } 21255373Smjacob } 21383027Smjacob isp_prt(isp, ISP_LOGTDEBUG0, 21483027Smjacob "Immediate Notify On Bus %d, status=0x%x seqid=0x%x", 21583027Smjacob bus, status, seqid); 21683027Smjacob 21755373Smjacob switch (status) { 21855373Smjacob case IN_MSG_RECEIVED: 21955373Smjacob case IN_IDE_RECEIVED: 22055373Smjacob if (IS_FC(isp)) { 221154704Smjacob isp_got_msg_fc(isp, (in_fcentry_t *)local); 22255373Smjacob } else { 223154704Smjacob isp_got_msg(isp, (in_entry_t *)local); 22455373Smjacob } 22555373Smjacob break; 22655373Smjacob case IN_RSRC_UNAVAIL: 22764090Smjacob isp_prt(isp, ISP_LOGWARN, "Firmware out of ATIOs"); 228154704Smjacob isp_notify_ack(isp, local); 22955373Smjacob break; 230154704Smjacob case IN_RESET: 231154704Smjacob isp_target_async(isp, 0, ASYNC_BUS_RESET); 232154704Smjacob break; 23398284Smjacob case IN_PORT_LOGOUT: 23455373Smjacob case IN_ABORT_TASK: 23555373Smjacob case IN_PORT_CHANGED: 23655373Smjacob case IN_GLOBAL_LOGO: 23798284Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, &local); 23855373Smjacob break; 23955373Smjacob default: 24064090Smjacob isp_prt(isp, ISP_LOGERR, 24164090Smjacob "bad status (0x%x) in isp_target_notify", status); 242154704Smjacob isp_notify_ack(isp, local); 24355373Smjacob break; 24455373Smjacob } 24555373Smjacob break; 24655373Smjacob 24755373Smjacob case RQSTYPE_NOTIFY_ACK: 24855373Smjacob /* 24955373Smjacob * The ISP is acknowledging our acknowledgement of an 25055373Smjacob * Immediate Notify entry for some asynchronous event. 25155373Smjacob */ 25255373Smjacob if (IS_FC(isp)) { 253154704Smjacob if (IS_2KLOGIN(isp)) 254154704Smjacob isp_get_notify_ack_fc_e(isp, nacke_fcp, 255154704Smjacob (na_fcentry_e_t *)local); 256154704Smjacob else 257154704Smjacob isp_get_notify_ack_fc(isp, nack_fcp, 258154704Smjacob (na_fcentry_t *)local); 25987635Smjacob nack_fcp = (na_fcentry_t *)local; 26064090Smjacob isp_prt(isp, ISP_LOGTDEBUG1, 26164090Smjacob "Notify Ack status=0x%x seqid 0x%x", 26264090Smjacob nack_fcp->na_status, nack_fcp->na_seqid); 26355373Smjacob } else { 26487635Smjacob isp_get_notify_ack(isp, nackp, (na_entry_t *)local); 26587635Smjacob nackp = (na_entry_t *)local; 26664090Smjacob isp_prt(isp, ISP_LOGTDEBUG1, 26764090Smjacob "Notify Ack event 0x%x status=0x%x seqid 0x%x", 26864090Smjacob nackp->na_event, nackp->na_status, nackp->na_seqid); 26955373Smjacob } 27055373Smjacob break; 27155373Smjacob default: 27264090Smjacob isp_prt(isp, ISP_LOGERR, 27387635Smjacob "Unknown entry type 0x%x in isp_target_notify", type); 27498284Smjacob rval = 0; 27555373Smjacob break; 27655373Smjacob } 27755373Smjacob#undef atiop 27855373Smjacob#undef at2iop 279154704Smjacob#undef at2eiop 28055373Smjacob#undef ctiop 28155373Smjacob#undef ct2iop 282154704Smjacob#undef ct2eiop 28355373Smjacob#undef lunenp 28455373Smjacob#undef inotp 28555373Smjacob#undef inot_fcp 286154704Smjacob#undef inote_fcp 28755373Smjacob#undef nackp 28855373Smjacob#undef nack_fcp 289154704Smjacob#undef nacke_fcp 29055373Smjacob#undef hdrp 29155373Smjacob return (rval); 29255373Smjacob} 29355373Smjacob 29455373Smjacob 29555373Smjacob/* 29655373Smjacob * Toggle (on/off) target mode for bus/target/lun 29755373Smjacob * 29855373Smjacob * The caller has checked for overlap and legality. 29955373Smjacob * 30055373Smjacob * Note that not all of bus, target or lun can be paid attention to. 30155373Smjacob * Note also that this action will not be complete until the f/w writes 30255373Smjacob * response entry. The caller is responsible for synchronizing this. 30355373Smjacob */ 30455373Smjacobint 30575196Smjacobisp_lun_cmd(struct ispsoftc *isp, int cmd, int bus, int tgt, int lun, 30677365Smjacob int cmd_cnt, int inot_cnt, u_int32_t opaque) 30755373Smjacob{ 30855373Smjacob lun_entry_t el; 30987635Smjacob u_int16_t nxti, optr; 31055373Smjacob void *outp; 31155373Smjacob 31255373Smjacob 31355373Smjacob MEMZERO(&el, sizeof (el)); 31457216Smjacob if (IS_DUALBUS(isp)) { 31557216Smjacob el.le_rsvd = (bus & 0x1) << 7; 31657216Smjacob } 31777365Smjacob el.le_cmd_count = cmd_cnt; 31877365Smjacob el.le_in_count = inot_cnt; 31955373Smjacob if (cmd == RQSTYPE_ENABLE_LUN) { 32055373Smjacob if (IS_SCSI(isp)) { 32161774Smjacob el.le_flags = LUN_TQAE|LUN_DISAD; 32255373Smjacob el.le_cdb6len = 12; 32355373Smjacob el.le_cdb7len = 12; 32455373Smjacob } 32555373Smjacob } else if (cmd == -RQSTYPE_ENABLE_LUN) { 32655373Smjacob cmd = RQSTYPE_ENABLE_LUN; 32755373Smjacob el.le_cmd_count = 0; 32855373Smjacob el.le_in_count = 0; 32955373Smjacob } else if (cmd == -RQSTYPE_MODIFY_LUN) { 33055373Smjacob cmd = RQSTYPE_MODIFY_LUN; 33155373Smjacob el.le_ops = LUN_CCDECR | LUN_INDECR; 33255373Smjacob } else { 33355373Smjacob el.le_ops = LUN_CCINCR | LUN_ININCR; 33455373Smjacob } 33555373Smjacob el.le_header.rqs_entry_type = cmd; 33655373Smjacob el.le_header.rqs_entry_count = 1; 33755373Smjacob el.le_reserved = opaque; 33855373Smjacob if (IS_SCSI(isp)) { 33955373Smjacob el.le_tgt = tgt; 34055373Smjacob el.le_lun = lun; 34183027Smjacob } else if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 34255373Smjacob el.le_lun = lun; 34355373Smjacob } 34475196Smjacob el.le_timeout = 2; 34555373Smjacob 34687635Smjacob if (isp_getrqentry(isp, &nxti, &optr, &outp)) { 34787635Smjacob isp_prt(isp, ISP_LOGERR, 34864090Smjacob "Request Queue Overflow in isp_lun_cmd"); 34955373Smjacob return (-1); 35055373Smjacob } 35155373Smjacob ISP_TDQE(isp, "isp_lun_cmd", (int) optr, &el); 35287635Smjacob isp_put_enable_lun(isp, &el, outp); 35387635Smjacob ISP_ADD_REQUEST(isp, nxti); 35455373Smjacob return (0); 35555373Smjacob} 35655373Smjacob 35755373Smjacob 35855373Smjacobint 35975196Smjacobisp_target_put_entry(struct ispsoftc *isp, void *ap) 36055373Smjacob{ 36155373Smjacob void *outp; 36287635Smjacob u_int16_t nxti, optr; 36355373Smjacob u_int8_t etype = ((isphdr_t *) ap)->rqs_entry_type; 36455373Smjacob 36587635Smjacob if (isp_getrqentry(isp, &nxti, &optr, &outp)) { 36664090Smjacob isp_prt(isp, ISP_LOGWARN, 36764090Smjacob "Request Queue Overflow in isp_target_put_entry"); 36855373Smjacob return (-1); 36955373Smjacob } 37055373Smjacob switch (etype) { 37155373Smjacob case RQSTYPE_ATIO: 37287635Smjacob isp_put_atio(isp, (at_entry_t *) ap, (at_entry_t *) outp); 37355373Smjacob break; 37455373Smjacob case RQSTYPE_ATIO2: 37587635Smjacob isp_put_atio2(isp, (at2_entry_t *) ap, (at2_entry_t *) outp); 37655373Smjacob break; 37755373Smjacob case RQSTYPE_CTIO: 37887635Smjacob isp_put_ctio(isp, (ct_entry_t *) ap, (ct_entry_t *) outp); 37955373Smjacob break; 38055373Smjacob case RQSTYPE_CTIO2: 38187635Smjacob isp_put_ctio2(isp, (ct2_entry_t *) ap, (ct2_entry_t *) outp); 38255373Smjacob break; 38355373Smjacob default: 38464090Smjacob isp_prt(isp, ISP_LOGERR, 38564090Smjacob "Unknown type 0x%x in isp_put_entry", etype); 38655373Smjacob return (-1); 38755373Smjacob } 38855373Smjacob 389120016Smjacob ISP_TDQE(isp, "isp_target_put_entry", (int) optr, ap); 39087635Smjacob ISP_ADD_REQUEST(isp, nxti); 39155373Smjacob return (0); 39255373Smjacob} 39355373Smjacob 39455373Smjacobint 39575196Smjacobisp_target_put_atio(struct ispsoftc *isp, void *arg) 39655373Smjacob{ 39755373Smjacob union { 39855373Smjacob at_entry_t _atio; 39955373Smjacob at2_entry_t _atio2; 400154704Smjacob at2e_entry_t _atio2e; 40155373Smjacob } atun; 40255373Smjacob 40355373Smjacob MEMZERO(&atun, sizeof atun); 40455373Smjacob if (IS_FC(isp)) { 40575196Smjacob at2_entry_t *aep = arg; 40655373Smjacob atun._atio2.at_header.rqs_entry_type = RQSTYPE_ATIO2; 40755373Smjacob atun._atio2.at_header.rqs_entry_count = 1; 40882843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 40975196Smjacob atun._atio2.at_scclun = (u_int16_t) aep->at_scclun; 41061774Smjacob } else { 41182843Smjacob atun._atio2.at_lun = (u_int8_t) aep->at_lun; 41261774Smjacob } 413154704Smjacob if (IS_2KLOGIN(isp)) { 414154704Smjacob atun._atio2e.at_iid = ((at2e_entry_t *)aep)->at_iid; 415154704Smjacob } else { 416154704Smjacob atun._atio2.at_iid = aep->at_iid; 417154704Smjacob } 418111004Smjacob atun._atio2.at_rxid = aep->at_rxid; 41955373Smjacob atun._atio2.at_status = CT_OK; 42055373Smjacob } else { 42175196Smjacob at_entry_t *aep = arg; 42255373Smjacob atun._atio.at_header.rqs_entry_type = RQSTYPE_ATIO; 42355373Smjacob atun._atio.at_header.rqs_entry_count = 1; 42475196Smjacob atun._atio.at_handle = aep->at_handle; 42575196Smjacob atun._atio.at_iid = aep->at_iid; 42675196Smjacob atun._atio.at_tgt = aep->at_tgt; 42775196Smjacob atun._atio.at_lun = aep->at_lun; 42875196Smjacob atun._atio.at_tag_type = aep->at_tag_type; 42975196Smjacob atun._atio.at_tag_val = aep->at_tag_val; 43075196Smjacob atun._atio.at_status = (aep->at_flags & AT_TQAE); 43175196Smjacob atun._atio.at_status |= CT_OK; 43255373Smjacob } 43355373Smjacob return (isp_target_put_entry(isp, &atun)); 43455373Smjacob} 43555373Smjacob 43655373Smjacob/* 43755373Smjacob * Command completion- both for handling cases of no resources or 43855373Smjacob * no blackhole driver, or other cases where we have to, inline, 43955373Smjacob * finish the command sanely, or for normal command completion. 44055373Smjacob * 44155373Smjacob * The 'completion' code value has the scsi status byte in the low 8 bits. 44255373Smjacob * If status is a CHECK CONDITION and bit 8 is nonzero, then bits 12..15 have 44355373Smjacob * the sense key and bits 16..23 have the ASCQ and bits 24..31 have the ASC 44455373Smjacob * values. 44555373Smjacob * 44655373Smjacob * NB: the key, asc, ascq, cannot be used for parallel SCSI as it doesn't 44775196Smjacob * NB: inline SCSI sense reporting. As such, we lose this information. XXX. 44855373Smjacob * 44955373Smjacob * For both parallel && fibre channel, we use the feature that does 45055373Smjacob * an automatic resource autoreplenish so we don't have then later do 45155373Smjacob * put of an atio to replenish the f/w's resource count. 45255373Smjacob */ 45355373Smjacob 45455373Smjacobint 45573319Smjacobisp_endcmd(struct ispsoftc *isp, void *arg, u_int32_t code, u_int16_t hdl) 45655373Smjacob{ 45755373Smjacob int sts; 45855373Smjacob union { 45955373Smjacob ct_entry_t _ctio; 46055373Smjacob ct2_entry_t _ctio2; 461154704Smjacob ct2e_entry_t _ctio2e; 46255373Smjacob } un; 46355373Smjacob 46455373Smjacob MEMZERO(&un, sizeof un); 46555373Smjacob sts = code & 0xff; 46655373Smjacob 46755373Smjacob if (IS_FC(isp)) { 46855373Smjacob at2_entry_t *aep = arg; 46955373Smjacob ct2_entry_t *cto = &un._ctio2; 47055373Smjacob 47155373Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 47255373Smjacob cto->ct_header.rqs_entry_count = 1; 47383027Smjacob if ((FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) == 0) { 47461774Smjacob cto->ct_lun = aep->at_lun; 47561774Smjacob } 476154704Smjacob if (IS_2KLOGIN(isp)) { 477154704Smjacob un._ctio2e.ct_iid = ((at2e_entry_t *)aep)->at_iid; 478154704Smjacob } else { 479154704Smjacob cto->ct_iid = aep->at_iid; 480154704Smjacob } 48155373Smjacob cto->ct_rxid = aep->at_rxid; 482125189Smjacob cto->rsp.m1.ct_scsi_status = sts; 48355373Smjacob cto->ct_flags = CT2_SENDSTATUS | CT2_NO_DATA | CT2_FLAG_MODE1; 48455373Smjacob if (hdl == 0) { 48555373Smjacob cto->ct_flags |= CT2_CCINCR; 48655373Smjacob } 48755373Smjacob if (aep->at_datalen) { 48855373Smjacob cto->ct_resid = aep->at_datalen; 48977365Smjacob cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER; 49055373Smjacob } 491125189Smjacob if (sts == SCSI_CHECK && (code & ECMD_SVALID)) { 49255373Smjacob cto->rsp.m1.ct_resp[0] = 0xf0; 49355373Smjacob cto->rsp.m1.ct_resp[2] = (code >> 12) & 0xf; 49455373Smjacob cto->rsp.m1.ct_resp[7] = 8; 49555373Smjacob cto->rsp.m1.ct_resp[12] = (code >> 24) & 0xff; 49655373Smjacob cto->rsp.m1.ct_resp[13] = (code >> 16) & 0xff; 49755373Smjacob cto->rsp.m1.ct_senselen = 16; 49877365Smjacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 49955373Smjacob } 50074232Smjacob cto->ct_syshandle = hdl; 50155373Smjacob } else { 50255373Smjacob at_entry_t *aep = arg; 50355373Smjacob ct_entry_t *cto = &un._ctio; 50455373Smjacob 50555373Smjacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO; 50655373Smjacob cto->ct_header.rqs_entry_count = 1; 50773319Smjacob cto->ct_fwhandle = aep->at_handle; 50855373Smjacob cto->ct_iid = aep->at_iid; 50955373Smjacob cto->ct_tgt = aep->at_tgt; 51055373Smjacob cto->ct_lun = aep->at_lun; 51155373Smjacob cto->ct_tag_type = aep->at_tag_type; 51255373Smjacob cto->ct_tag_val = aep->at_tag_val; 51375196Smjacob if (aep->at_flags & AT_TQAE) { 51475196Smjacob cto->ct_flags |= CT_TQAE; 51575196Smjacob } 51655373Smjacob cto->ct_flags = CT_SENDSTATUS | CT_NO_DATA; 51755373Smjacob if (hdl == 0) { 51855373Smjacob cto->ct_flags |= CT_CCINCR; 51955373Smjacob } 52055373Smjacob cto->ct_scsi_status = sts; 52174232Smjacob cto->ct_syshandle = hdl; 52255373Smjacob } 52355373Smjacob return (isp_target_put_entry(isp, &un)); 52455373Smjacob} 52555373Smjacob 52698284Smjacobint 52775196Smjacobisp_target_async(struct ispsoftc *isp, int bus, int event) 52855373Smjacob{ 529154704Smjacob tmd_notify_t notify; 53055373Smjacob 531154704Smjacob MEMZERO(¬ify, sizeof (tmd_notify_t)); 532154704Smjacob notify.nt_hba = isp; 533154704Smjacob /* nt_str set in outer layers */ 534154704Smjacob notify.nt_iid = INI_ANY; 535154704Smjacob /* nt_tgt set in outer layers */ 536154704Smjacob notify.nt_lun = LUN_ANY; 537154704Smjacob notify.nt_tagval = TAG_ANY; 538154704Smjacob 539154704Smjacob if (IS_SCSI(isp)) { 540154704Smjacob TAG_INSERT_BUS(notify.nt_tagval, bus); 541154704Smjacob } 542154704Smjacob 54355373Smjacob switch (event) { 544154704Smjacob case ASYNC_LOOP_UP: 545154704Smjacob case ASYNC_PTPMODE: 546154704Smjacob notify.nt_ncode = NT_LINK_UP; 547154704Smjacob (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 548154704Smjacob break; 549154704Smjacob case ASYNC_LOOP_DOWN: 550154704Smjacob notify.nt_ncode = NT_LINK_DOWN; 551154704Smjacob (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 552154704Smjacob break; 55383027Smjacob case ASYNC_LIP_F8: 55455373Smjacob case ASYNC_LIP_OCCURRED: 55583027Smjacob case ASYNC_LOOP_RESET: 556154704Smjacob notify.nt_ncode = NT_LIP_RESET; 557154704Smjacob (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 558154704Smjacob break; 55955373Smjacob case ASYNC_BUS_RESET: 560154704Smjacob case ASYNC_TIMEOUT_RESET: /* XXX: where does this come from ? */ 561154704Smjacob notify.nt_ncode = NT_BUS_RESET; 562154704Smjacob (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 56355373Smjacob break; 56455373Smjacob case ASYNC_DEVICE_RESET: 565154704Smjacob notify.nt_ncode = NT_TARGET_RESET; 566154704Smjacob (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 567154704Smjacob break; 568154704Smjacob case ASYNC_CTIO_DONE: 569154704Smjacob { 570154704Smjacob uint8_t storage[QENTRY_LEN]; 571154704Smjacob memset(storage, 0, QENTRY_LEN); 57255373Smjacob if (IS_FC(isp)) { 573154704Smjacob ct2_entry_t *ct = (ct2_entry_t *) storage; 574154704Smjacob ct->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 575154704Smjacob ct->ct_status = CT_OK; 576154704Smjacob ct->ct_syshandle = bus; 577154704Smjacob ct->ct_flags = CT2_SENDSTATUS|CT2_FASTPOST; 57855373Smjacob } else { 579154704Smjacob ct_entry_t *ct = (ct_entry_t *) storage; 580154704Smjacob ct->ct_header.rqs_entry_type = RQSTYPE_CTIO; 581154704Smjacob ct->ct_status = CT_OK; 582154704Smjacob ct->ct_fwhandle = bus; 583154704Smjacob ct->ct_flags = CT_SENDSTATUS; 58455373Smjacob } 585154704Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, storage); 586120016Smjacob return (0); 587154704Smjacob } 58855373Smjacob default: 58964090Smjacob isp_prt(isp, ISP_LOGERR, 59064090Smjacob "isp_target_async: unknown event 0x%x", event); 591154704Smjacob if (isp->isp_state == ISP_RUNSTATE) { 592154704Smjacob isp_notify_ack(isp, NULL); 593154704Smjacob } 59455373Smjacob break; 59555373Smjacob } 596154704Smjacob return (0); 59755373Smjacob} 59855373Smjacob 59955373Smjacob 60055373Smjacob/* 60155373Smjacob * Process a received message. 60255373Smjacob * The ISP firmware can handle most messages, there are only 60355373Smjacob * a few that we need to deal with: 60455373Smjacob * - abort: clean up the current command 60555373Smjacob * - abort tag and clear queue 60655373Smjacob */ 60755373Smjacob 60855373Smjacobstatic void 609154704Smjacobisp_got_msg(struct ispsoftc *isp, in_entry_t *inp) 61055373Smjacob{ 611154704Smjacob tmd_notify_t nt; 61255373Smjacob u_int8_t status = inp->in_status & ~QLTM_SVALID; 61355373Smjacob 614154704Smjacob MEMZERO(&nt, sizeof (nt)); 615154704Smjacob nt.nt_hba = isp; 616154704Smjacob /* nt_str set in outer layers */ 617154704Smjacob nt.nt_iid = GET_IID_VAL(inp->in_iid); 618154704Smjacob nt.nt_tgt = inp->in_tgt; 619154704Smjacob nt.nt_lun = inp->in_lun; 620154704Smjacob IN_MAKE_TAGID(nt.nt_tagval, 0, inp); 621154704Smjacob nt.nt_lreserved = inp; 622154704Smjacob 62355373Smjacob if (status == IN_IDE_RECEIVED || status == IN_MSG_RECEIVED) { 624154704Smjacob switch (inp->in_msg[0]) { 625154704Smjacob case MSG_ABORT: 626154704Smjacob nt.nt_ncode = NT_ABORT_TASK_SET; 627154704Smjacob break; 628154704Smjacob case MSG_BUS_DEV_RESET: 629154704Smjacob nt.nt_ncode = NT_TARGET_RESET; 630154704Smjacob break; 631154704Smjacob case MSG_ABORT_TAG: 632154704Smjacob nt.nt_ncode = NT_ABORT_TASK; 633154704Smjacob break; 634154704Smjacob case MSG_CLEAR_QUEUE: 635154704Smjacob nt.nt_ncode = NT_CLEAR_TASK_SET; 636154704Smjacob break; 637154704Smjacob case MSG_REL_RECOVERY: 638154704Smjacob nt.nt_ncode = NT_CLEAR_ACA; 639154704Smjacob break; 640154704Smjacob case MSG_TERM_IO_PROC: 641154704Smjacob nt.nt_ncode = NT_ABORT_TASK; 642154704Smjacob break; 643154704Smjacob case MSG_LUN_RESET: 644154704Smjacob nt.nt_ncode = NT_LUN_RESET; 645154704Smjacob break; 646154704Smjacob default: 647154704Smjacob isp_prt(isp, ISP_LOGERR, 648154704Smjacob "unhandled message 0x%x", inp->in_msg[0]); 649154704Smjacob isp_notify_ack(isp, inp); 650154704Smjacob return; 651154704Smjacob } 652154704Smjacob (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt); 65355373Smjacob } else { 65464090Smjacob isp_prt(isp, ISP_LOGERR, 65564090Smjacob "unknown immediate notify status 0x%x", inp->in_status); 656154704Smjacob isp_notify_ack(isp, inp); 65755373Smjacob } 65855373Smjacob} 65955373Smjacob 66055373Smjacob/* 66155373Smjacob * Synthesize a message from the task management flags in a FCP_CMND_IU. 66255373Smjacob */ 66355373Smjacobstatic void 664154704Smjacobisp_got_msg_fc(struct ispsoftc *isp, in_fcentry_t *inp) 66555373Smjacob{ 666154704Smjacob tmd_notify_t nt; 667154704Smjacob static const char f1[] = "%s from iid 0x%08x%08x lun %d seq 0x%x"; 66875196Smjacob static const char f2[] = 669154704Smjacob "unknown %s 0x%x lun %d iid 0x%08x%08x task flags 0x%x seq 0x%x\n"; 67055373Smjacob 671154704Smjacob MEMZERO(&nt, sizeof (tmd_notify_t)); 672154704Smjacob nt.nt_hba = isp; 673154704Smjacob /* 674154704Smjacob * XXX: LOOK UP TRANSLATION IN CURRENT LPORTDB 675154704Smjacob */ 676154704Smjacob if (IS_2KLOGIN(isp)) { 677154704Smjacob nt.nt_iid = ((in_fcentry_e_t *)inp)->in_iid; 678154704Smjacob } else { 679154704Smjacob nt.nt_iid = inp->in_iid; /* possibly reset in outer layer */ 680154704Smjacob } 681154704Smjacob /* nt_tgt set in outer layers */ 68282843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 683154704Smjacob nt.nt_lun = inp->in_scclun; 68482843Smjacob } else { 685154704Smjacob nt.nt_lun = inp->in_lun; 68682843Smjacob } 687154704Smjacob IN_FC_MAKE_TAGID(nt.nt_tagval, 0, inp); 688154704Smjacob nt.nt_lreserved = inp; 68982843Smjacob 69055373Smjacob if (inp->in_status != IN_MSG_RECEIVED) { 69164090Smjacob isp_prt(isp, ISP_LOGINFO, f2, "immediate notify status", 692154704Smjacob inp->in_status, nt.nt_lun, (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, 69355373Smjacob inp->in_task_flags, inp->in_seqid); 694154704Smjacob isp_notify_ack(isp, inp); 695154704Smjacob return; 696154704Smjacob } 697154704Smjacob 698154704Smjacob if (inp->in_task_flags & TASK_FLAGS_ABORT_TASK_SET) { 699154704Smjacob isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK SET", 700154704Smjacob (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid); 701154704Smjacob nt.nt_ncode = NT_ABORT_TASK_SET; 702154704Smjacob } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_TASK_SET) { 703154704Smjacob isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET", 704154704Smjacob (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid); 705154704Smjacob nt.nt_ncode = NT_CLEAR_TASK_SET; 706154704Smjacob } else if (inp->in_task_flags & TASK_FLAGS_LUN_RESET) { 707154704Smjacob isp_prt(isp, ISP_LOGINFO, f1, "LUN RESET", 708154704Smjacob (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid); 709154704Smjacob nt.nt_ncode = NT_LUN_RESET; 710154704Smjacob } else if (inp->in_task_flags & TASK_FLAGS_TARGET_RESET) { 711154704Smjacob isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET", 712154704Smjacob (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid); 713154704Smjacob nt.nt_ncode = NT_TARGET_RESET; 714154704Smjacob } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_ACA) { 715154704Smjacob isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA", 716154704Smjacob (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, nt.nt_lun, inp->in_seqid); 717154704Smjacob nt.nt_ncode = NT_CLEAR_ACA; 71855373Smjacob } else { 719154704Smjacob isp_prt(isp, ISP_LOGWARN, f2, "task flag", 720154704Smjacob inp->in_status, nt.nt_lun, (u_int32_t) (nt.nt_iid >> 32), (u_int32_t) nt.nt_iid, 721154704Smjacob inp->in_task_flags, inp->in_seqid); 722154704Smjacob isp_notify_ack(isp, inp); 723154704Smjacob return; 72455373Smjacob } 725154704Smjacob (void) isp_async(isp, ISPASYNC_TARGET_NOTIFY, &nt); 72655373Smjacob} 72755373Smjacob 728154704Smjacobvoid 72975196Smjacobisp_notify_ack(struct ispsoftc *isp, void *arg) 73055373Smjacob{ 73155373Smjacob char storage[QENTRY_LEN]; 73287635Smjacob u_int16_t nxti, optr; 73355373Smjacob void *outp; 73455373Smjacob 73587635Smjacob if (isp_getrqentry(isp, &nxti, &optr, &outp)) { 73664090Smjacob isp_prt(isp, ISP_LOGWARN, 73764090Smjacob "Request Queue Overflow For isp_notify_ack"); 73855373Smjacob return; 73955373Smjacob } 74055373Smjacob 74156006Smjacob MEMZERO(storage, QENTRY_LEN); 74255373Smjacob 74355373Smjacob if (IS_FC(isp)) { 74455373Smjacob na_fcentry_t *na = (na_fcentry_t *) storage; 74555373Smjacob if (arg) { 74655373Smjacob in_fcentry_t *inp = arg; 74756006Smjacob MEMCPY(storage, arg, sizeof (isphdr_t)); 748154704Smjacob if (IS_2KLOGIN(isp)) { 749154704Smjacob ((na_fcentry_e_t *)na)->na_iid = ((in_fcentry_e_t *)inp)->in_iid; 750154704Smjacob } else { 751154704Smjacob na->na_iid = inp->in_iid; 752154704Smjacob } 75382843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 75461774Smjacob na->na_lun = inp->in_scclun; 75561774Smjacob } else { 75661774Smjacob na->na_lun = inp->in_lun; 75761774Smjacob } 75855373Smjacob na->na_task_flags = inp->in_task_flags; 75955373Smjacob na->na_seqid = inp->in_seqid; 76055373Smjacob na->na_flags = NAFC_RCOUNT; 76190224Smjacob na->na_status = inp->in_status; 76255373Smjacob if (inp->in_status == IN_RESET) { 76355373Smjacob na->na_flags |= NAFC_RST_CLRD; 76455373Smjacob } 76555373Smjacob } else { 76655373Smjacob na->na_flags = NAFC_RST_CLRD; 76755373Smjacob } 76859453Smjacob na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; 76959453Smjacob na->na_header.rqs_entry_count = 1; 770154704Smjacob if (IS_2KLOGIN(isp)) { 771154704Smjacob isp_put_notify_ack_fc_e(isp, (na_fcentry_e_t *) na, (na_fcentry_e_t *)outp); 772154704Smjacob } else { 773154704Smjacob isp_put_notify_ack_fc(isp, na, (na_fcentry_t *)outp); 774154704Smjacob } 77555373Smjacob } else { 77655373Smjacob na_entry_t *na = (na_entry_t *) storage; 77755373Smjacob if (arg) { 77855373Smjacob in_entry_t *inp = arg; 77956006Smjacob MEMCPY(storage, arg, sizeof (isphdr_t)); 78055373Smjacob na->na_iid = inp->in_iid; 78155373Smjacob na->na_lun = inp->in_lun; 78255373Smjacob na->na_tgt = inp->in_tgt; 78355373Smjacob na->na_seqid = inp->in_seqid; 78455373Smjacob if (inp->in_status == IN_RESET) { 78559453Smjacob na->na_event = NA_RST_CLRD; 78655373Smjacob } 78755373Smjacob } else { 78859453Smjacob na->na_event = NA_RST_CLRD; 78955373Smjacob } 79059453Smjacob na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; 79159453Smjacob na->na_header.rqs_entry_count = 1; 79287635Smjacob isp_put_notify_ack(isp, na, (na_entry_t *)outp); 79355373Smjacob } 79455373Smjacob ISP_TDQE(isp, "isp_notify_ack", (int) optr, storage); 79587635Smjacob ISP_ADD_REQUEST(isp, nxti); 79655373Smjacob} 79755373Smjacob 79855373Smjacobstatic void 79975196Smjacobisp_handle_atio(struct ispsoftc *isp, at_entry_t *aep) 80055373Smjacob{ 80155373Smjacob int lun; 80255373Smjacob lun = aep->at_lun; 80355373Smjacob /* 80455373Smjacob * The firmware status (except for the QLTM_SVALID bit) indicates 80555373Smjacob * why this ATIO was sent to us. 80655373Smjacob * 80755373Smjacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 80855373Smjacob * 80955373Smjacob * If the DISCONNECTS DISABLED bit is set in the flags field, 81055373Smjacob * we're still connected on the SCSI bus - i.e. the initiator 81155373Smjacob * did not set DiscPriv in the identify message. We don't care 81255373Smjacob * about this so it's ignored. 81355373Smjacob */ 81455373Smjacob 81555373Smjacob switch(aep->at_status & ~QLTM_SVALID) { 81655373Smjacob case AT_PATH_INVALID: 81755373Smjacob /* 81855373Smjacob * ATIO rejected by the firmware due to disabled lun. 81955373Smjacob */ 82064090Smjacob isp_prt(isp, ISP_LOGERR, 82164090Smjacob "rejected ATIO for disabled lun %d", lun); 82255373Smjacob break; 82355373Smjacob case AT_NOCAP: 82455373Smjacob /* 82555373Smjacob * Requested Capability not available 82655373Smjacob * We sent an ATIO that overflowed the firmware's 82755373Smjacob * command resource count. 82855373Smjacob */ 82964090Smjacob isp_prt(isp, ISP_LOGERR, 83064090Smjacob "rejected ATIO for lun %d because of command count" 83164090Smjacob " 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 84087635Smjacob * resource count in the Enable Lun entry and do 84155373Smjacob * not increment it. Therefore we should never get 84255373Smjacob * this status here. 84355373Smjacob */ 84483027Smjacob isp_prt(isp, ISP_LOGERR, atiocope, lun, 84583027Smjacob GET_BUS_VAL(aep->at_iid)); 84655373Smjacob break; 84755373Smjacob 84855373Smjacob case AT_CDB: /* Got a CDB */ 84955373Smjacob case AT_PHASE_ERROR: /* Bus Phase Sequence Error */ 85055373Smjacob /* 85155373Smjacob * Punt to platform specific layer. 85255373Smjacob */ 85355373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep); 85455373Smjacob break; 85555373Smjacob 85655373Smjacob case AT_RESET: 85755373Smjacob /* 858108470Sschweikh * A bus reset came along and blew away this command. Why 85955373Smjacob * they do this in addition the async event code stuff, 86055373Smjacob * I dunno. 86155373Smjacob * 86255373Smjacob * Ignore it because the async event will clear things 86355373Smjacob * up for us. 86455373Smjacob */ 86583027Smjacob isp_prt(isp, ISP_LOGWARN, atior, lun, 86683027Smjacob GET_IID_VAL(aep->at_iid), GET_BUS_VAL(aep->at_iid)); 86755373Smjacob break; 86855373Smjacob 86955373Smjacob 87055373Smjacob default: 87164090Smjacob isp_prt(isp, ISP_LOGERR, 87264090Smjacob "Unknown ATIO status 0x%x from initiator %d for lun %d", 87364090Smjacob aep->at_status, aep->at_iid, lun); 87475196Smjacob (void) isp_target_put_atio(isp, aep); 87555373Smjacob break; 87655373Smjacob } 87755373Smjacob} 87855373Smjacob 87955373Smjacobstatic void 88075196Smjacobisp_handle_atio2(struct ispsoftc *isp, at2_entry_t *aep) 88155373Smjacob{ 882154704Smjacob int lun, iid; 88361774Smjacob 88482843Smjacob if (FCPARAM(isp)->isp_fwattr & ISP_FW_ATTR_SCCLUN) { 88561774Smjacob lun = aep->at_scclun; 88661774Smjacob } else { 88761774Smjacob lun = aep->at_lun; 88861774Smjacob } 88961774Smjacob 890154704Smjacob if (IS_2KLOGIN(isp)) { 891154704Smjacob iid = ((at2e_entry_t *)aep)->at_iid; 892154704Smjacob } else { 893154704Smjacob iid = aep->at_iid; 894154704Smjacob } 895154704Smjacob 89655373Smjacob /* 89755373Smjacob * The firmware status (except for the QLTM_SVALID bit) indicates 89855373Smjacob * why this ATIO was sent to us. 89955373Smjacob * 90055373Smjacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 90155373Smjacob * 90255373Smjacob * If the DISCONNECTS DISABLED bit is set in the flags field, 90355373Smjacob * we're still connected on the SCSI bus - i.e. the initiator 90455373Smjacob * did not set DiscPriv in the identify message. We don't care 90555373Smjacob * about this so it's ignored. 90655373Smjacob */ 90755373Smjacob 90855373Smjacob switch(aep->at_status & ~QLTM_SVALID) { 90955373Smjacob case AT_PATH_INVALID: 91055373Smjacob /* 91155373Smjacob * ATIO rejected by the firmware due to disabled lun. 91255373Smjacob */ 91364090Smjacob isp_prt(isp, ISP_LOGERR, 91464090Smjacob "rejected ATIO2 for disabled lun %d", lun); 91555373Smjacob break; 91655373Smjacob case AT_NOCAP: 91755373Smjacob /* 91855373Smjacob * Requested Capability not available 91955373Smjacob * We sent an ATIO that overflowed the firmware's 92055373Smjacob * command resource count. 92155373Smjacob */ 92264090Smjacob isp_prt(isp, ISP_LOGERR, 92364090Smjacob "rejected ATIO2 for lun %d- command count overflow", lun); 92455373Smjacob break; 92555373Smjacob 92655373Smjacob case AT_BDR_MSG: 92755373Smjacob /* 92855373Smjacob * If we send an ATIO to the firmware to increment 92955373Smjacob * its command resource count, and the firmware is 93055373Smjacob * recovering from a Bus Device Reset, it returns 93155373Smjacob * the ATIO with this status. We set the command 93255373Smjacob * resource count in the Enable Lun entry and no 93355373Smjacob * not increment it. Therefore we should never get 93455373Smjacob * this status here. 93555373Smjacob */ 93683027Smjacob isp_prt(isp, ISP_LOGERR, atiocope, lun, 0); 93755373Smjacob break; 93855373Smjacob 93955373Smjacob case AT_CDB: /* Got a CDB */ 94055373Smjacob /* 94155373Smjacob * Punt to platform specific layer. 94255373Smjacob */ 94355373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, aep); 94455373Smjacob break; 94555373Smjacob 94655373Smjacob case AT_RESET: 94755373Smjacob /* 94855373Smjacob * A bus reset came along an blew away this command. Why 94955373Smjacob * they do this in addition the async event code stuff, 95055373Smjacob * I dunno. 95155373Smjacob * 95255373Smjacob * Ignore it because the async event will clear things 95355373Smjacob * up for us. 95455373Smjacob */ 955154704Smjacob isp_prt(isp, ISP_LOGERR, atior, lun, iid, 0); 95655373Smjacob break; 95755373Smjacob 95855373Smjacob 95955373Smjacob default: 96064090Smjacob isp_prt(isp, ISP_LOGERR, 96164090Smjacob "Unknown ATIO2 status 0x%x from initiator %d for lun %d", 962154704Smjacob aep->at_status, iid, lun); 96375196Smjacob (void) isp_target_put_atio(isp, aep); 96455373Smjacob break; 96555373Smjacob } 96655373Smjacob} 96755373Smjacob 96855373Smjacobstatic void 96975196Smjacobisp_handle_ctio(struct ispsoftc *isp, ct_entry_t *ct) 97055373Smjacob{ 97174232Smjacob void *xs; 97264090Smjacob int pl = ISP_LOGTDEBUG2; 97355373Smjacob char *fmsg = NULL; 97455373Smjacob 97574232Smjacob if (ct->ct_syshandle) { 976129643Snjl xs = isp_find_xs_tgt(isp, ct->ct_syshandle); 97755373Smjacob if (xs == NULL) 97864090Smjacob pl = ISP_LOGALL; 97955373Smjacob } else { 98055373Smjacob xs = NULL; 98155373Smjacob } 98255373Smjacob 98355373Smjacob switch(ct->ct_status & ~QLTM_SVALID) { 98455373Smjacob case CT_OK: 98555373Smjacob /* 98655373Smjacob * There are generally 3 possibilities as to why we'd get 98755373Smjacob * this condition: 98855373Smjacob * We disconnected after receiving a CDB. 98955373Smjacob * We sent or received data. 99055373Smjacob * We sent status & command complete. 99155373Smjacob */ 99255373Smjacob 99359453Smjacob if (ct->ct_flags & CT_SENDSTATUS) { 99459453Smjacob break; 99559453Smjacob } else if ((ct->ct_flags & CT_DATAMASK) == CT_NO_DATA) { 99655373Smjacob /* 99755373Smjacob * Nothing to do in this case. 99855373Smjacob */ 99964090Smjacob isp_prt(isp, pl, "CTIO- iid %d disconnected OK", 100064090Smjacob ct->ct_iid); 100155373Smjacob return; 100255373Smjacob } 100355373Smjacob break; 100455373Smjacob 100555373Smjacob case CT_BDR_MSG: 100655373Smjacob /* 100755373Smjacob * Bus Device Reset message received or the SCSI Bus has 100855373Smjacob * been Reset; the firmware has gone to Bus Free. 100955373Smjacob * 101055373Smjacob * The firmware generates an async mailbox interupt to 101155373Smjacob * notify us of this and returns outstanding CTIOs with this 101255373Smjacob * status. These CTIOs are handled in that same way as 101355373Smjacob * CT_ABORTED ones, so just fall through here. 101455373Smjacob */ 101555373Smjacob fmsg = "Bus Device Reset"; 101655373Smjacob /*FALLTHROUGH*/ 101755373Smjacob case CT_RESET: 101855373Smjacob if (fmsg == NULL) 101955373Smjacob fmsg = "Bus Reset"; 102055373Smjacob /*FALLTHROUGH*/ 102155373Smjacob case CT_ABORTED: 102255373Smjacob /* 102355373Smjacob * When an Abort message is received the firmware goes to 102455373Smjacob * Bus Free and returns all outstanding CTIOs with the status 102555373Smjacob * set, then sends us an Immediate Notify entry. 102655373Smjacob */ 102755373Smjacob if (fmsg == NULL) 102883027Smjacob fmsg = "ABORT TAG message sent by Initiator"; 102955373Smjacob 103064090Smjacob isp_prt(isp, ISP_LOGWARN, "CTIO destroyed by %s", fmsg); 103155373Smjacob break; 103255373Smjacob 103355373Smjacob case CT_INVAL: 103455373Smjacob /* 103555373Smjacob * CTIO rejected by the firmware due to disabled lun. 103655373Smjacob * "Cannot Happen". 103755373Smjacob */ 103864090Smjacob isp_prt(isp, ISP_LOGERR, 103964090Smjacob "Firmware rejected CTIO for disabled lun %d", 104064090Smjacob ct->ct_lun); 104155373Smjacob break; 104255373Smjacob 104355373Smjacob case CT_NOPATH: 104455373Smjacob /* 104555373Smjacob * CTIO rejected by the firmware due "no path for the 104655373Smjacob * nondisconnecting nexus specified". This means that 104755373Smjacob * we tried to access the bus while a non-disconnecting 104855373Smjacob * command is in process. 104955373Smjacob */ 105064090Smjacob isp_prt(isp, ISP_LOGERR, 105164090Smjacob "Firmware rejected CTIO for bad nexus %d/%d/%d", 105264090Smjacob ct->ct_iid, ct->ct_tgt, ct->ct_lun); 105355373Smjacob break; 105455373Smjacob 105555373Smjacob case CT_RSELTMO: 105655373Smjacob fmsg = "Reselection"; 105755373Smjacob /*FALLTHROUGH*/ 105855373Smjacob case CT_TIMEOUT: 105955373Smjacob if (fmsg == NULL) 106055373Smjacob fmsg = "Command"; 106164090Smjacob isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg); 106255373Smjacob break; 106355373Smjacob 106475196Smjacob case CT_PANIC: 106575196Smjacob if (fmsg == NULL) 106675196Smjacob fmsg = "Unrecoverable Error"; 106775196Smjacob /*FALLTHROUGH*/ 106855373Smjacob case CT_ERR: 106975196Smjacob if (fmsg == NULL) 107075196Smjacob fmsg = "Completed with Error"; 107155373Smjacob /*FALLTHROUGH*/ 107255373Smjacob case CT_PHASE_ERROR: 107355373Smjacob if (fmsg == NULL) 107455373Smjacob fmsg = "Phase Sequence Error"; 107555373Smjacob /*FALLTHROUGH*/ 107655373Smjacob case CT_TERMINATED: 107755373Smjacob if (fmsg == NULL) 107855373Smjacob fmsg = "terminated by TERMINATE TRANSFER"; 107955373Smjacob /*FALLTHROUGH*/ 108055373Smjacob case CT_NOACK: 108155373Smjacob if (fmsg == NULL) 108255373Smjacob fmsg = "unacknowledged Immediate Notify pending"; 108364090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg); 108455373Smjacob break; 108555373Smjacob default: 108664090Smjacob isp_prt(isp, ISP_LOGERR, "Unknown CTIO status 0x%x", 108755373Smjacob ct->ct_status & ~QLTM_SVALID); 108855373Smjacob break; 108955373Smjacob } 109055373Smjacob 109155373Smjacob if (xs == NULL) { 109255373Smjacob /* 109355373Smjacob * There may be more than one CTIO for a data transfer, 109455373Smjacob * or this may be a status CTIO we're not monitoring. 109555373Smjacob * 109655373Smjacob * The assumption is that they'll all be returned in the 109755373Smjacob * order we got them. 109855373Smjacob */ 109974232Smjacob if (ct->ct_syshandle == 0) { 110055373Smjacob if ((ct->ct_flags & CT_SENDSTATUS) == 0) { 110164090Smjacob isp_prt(isp, pl, 110264090Smjacob "intermediate CTIO completed ok"); 110355373Smjacob } else { 110464090Smjacob isp_prt(isp, pl, 110564090Smjacob "unmonitored CTIO completed ok"); 110655373Smjacob } 110755373Smjacob } else { 110864090Smjacob isp_prt(isp, pl, 110964090Smjacob "NO xs for CTIO (handle 0x%x) status 0x%x", 111074232Smjacob ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); 111155373Smjacob } 111255373Smjacob } else { 111377365Smjacob /* 111477365Smjacob * Final CTIO completed. Release DMA resources and 111577365Smjacob * notify platform dependent layers. 111677365Smjacob */ 111777365Smjacob if ((ct->ct_flags & CT_DATAMASK) != CT_NO_DATA) { 111874232Smjacob ISP_DMAFREE(isp, xs, ct->ct_syshandle); 111955373Smjacob } 112075196Smjacob isp_prt(isp, pl, "final CTIO complete"); 112155373Smjacob /* 112255373Smjacob * The platform layer will destroy the handle if appropriate. 112355373Smjacob */ 112475196Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct); 112555373Smjacob } 112655373Smjacob} 112755373Smjacob 112855373Smjacobstatic void 112975196Smjacobisp_handle_ctio2(struct ispsoftc *isp, ct2_entry_t *ct) 113055373Smjacob{ 113164090Smjacob XS_T *xs; 113264090Smjacob int pl = ISP_LOGTDEBUG2; 113355373Smjacob char *fmsg = NULL; 113455373Smjacob 113574232Smjacob if (ct->ct_syshandle) { 1136129643Snjl xs = isp_find_xs_tgt(isp, ct->ct_syshandle); 113755373Smjacob if (xs == NULL) 113864090Smjacob pl = ISP_LOGALL; 113955373Smjacob } else { 114055373Smjacob xs = NULL; 114155373Smjacob } 114255373Smjacob 114355373Smjacob switch(ct->ct_status & ~QLTM_SVALID) { 114477365Smjacob case CT_BUS_ERROR: 114577365Smjacob isp_prt(isp, ISP_LOGERR, "PCI DMA Bus Error"); 114677365Smjacob /* FALL Through */ 114777365Smjacob case CT_DATA_OVER: 114877365Smjacob case CT_DATA_UNDER: 114955373Smjacob case CT_OK: 115055373Smjacob /* 115155373Smjacob * There are generally 2 possibilities as to why we'd get 115255373Smjacob * this condition: 115355373Smjacob * We sent or received data. 115455373Smjacob * We sent status & command complete. 115555373Smjacob */ 115655373Smjacob 115755373Smjacob break; 115855373Smjacob 115955373Smjacob case CT_BDR_MSG: 116055373Smjacob /* 116177365Smjacob * Target Reset function received. 116255373Smjacob * 116355373Smjacob * The firmware generates an async mailbox interupt to 116455373Smjacob * notify us of this and returns outstanding CTIOs with this 116555373Smjacob * status. These CTIOs are handled in that same way as 116655373Smjacob * CT_ABORTED ones, so just fall through here. 116755373Smjacob */ 116877365Smjacob fmsg = "TARGET RESET Task Management Function Received"; 116955373Smjacob /*FALLTHROUGH*/ 117055373Smjacob case CT_RESET: 117155373Smjacob if (fmsg == NULL) 117277365Smjacob fmsg = "LIP Reset"; 117355373Smjacob /*FALLTHROUGH*/ 117455373Smjacob case CT_ABORTED: 117555373Smjacob /* 117655373Smjacob * When an Abort message is received the firmware goes to 117755373Smjacob * Bus Free and returns all outstanding CTIOs with the status 117855373Smjacob * set, then sends us an Immediate Notify entry. 117955373Smjacob */ 118055373Smjacob if (fmsg == NULL) 118177365Smjacob fmsg = "ABORT Task Management Function Received"; 118255373Smjacob 118364090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO2 destroyed by %s", fmsg); 118455373Smjacob break; 118555373Smjacob 118655373Smjacob case CT_INVAL: 118755373Smjacob /* 118856006Smjacob * CTIO rejected by the firmware - invalid data direction. 118955373Smjacob */ 1190120016Smjacob isp_prt(isp, ISP_LOGERR, "CTIO2 had wrong data direction"); 119155373Smjacob break; 119255373Smjacob 119355373Smjacob case CT_RSELTMO: 119477365Smjacob fmsg = "failure to reconnect to initiator"; 119555373Smjacob /*FALLTHROUGH*/ 119655373Smjacob case CT_TIMEOUT: 119755373Smjacob if (fmsg == NULL) 119877365Smjacob fmsg = "command"; 119964090Smjacob isp_prt(isp, ISP_LOGERR, "Firmware timed out on %s", fmsg); 120055373Smjacob break; 120155373Smjacob 120255373Smjacob case CT_ERR: 120355373Smjacob fmsg = "Completed with Error"; 120455373Smjacob /*FALLTHROUGH*/ 120555373Smjacob case CT_LOGOUT: 120655373Smjacob if (fmsg == NULL) 120755373Smjacob fmsg = "Port Logout"; 120855373Smjacob /*FALLTHROUGH*/ 120955373Smjacob case CT_PORTNOTAVAIL: 121055373Smjacob if (fmsg == NULL) 121155373Smjacob fmsg = "Port not available"; 1212115521Sphk /*FALLTHROUGH*/ 121377365Smjacob case CT_PORTCHANGED: 121477365Smjacob if (fmsg == NULL) 121577365Smjacob fmsg = "Port Changed"; 1216115521Sphk /*FALLTHROUGH*/ 121755373Smjacob case CT_NOACK: 121855373Smjacob if (fmsg == NULL) 121955373Smjacob fmsg = "unacknowledged Immediate Notify pending"; 122064090Smjacob isp_prt(isp, ISP_LOGERR, "CTIO returned by f/w- %s", fmsg); 122155373Smjacob break; 122255373Smjacob 122355373Smjacob case CT_INVRXID: 122455373Smjacob /* 122555373Smjacob * CTIO rejected by the firmware because an invalid RX_ID. 122655373Smjacob * Just print a message. 122755373Smjacob */ 122864090Smjacob isp_prt(isp, ISP_LOGERR, 122964090Smjacob "CTIO2 completed with Invalid RX_ID 0x%x", ct->ct_rxid); 123055373Smjacob break; 123155373Smjacob 123255373Smjacob default: 123375196Smjacob isp_prt(isp, ISP_LOGERR, "Unknown CTIO2 status 0x%x", 123464090Smjacob ct->ct_status & ~QLTM_SVALID); 123555373Smjacob break; 123655373Smjacob } 123755373Smjacob 123855373Smjacob if (xs == NULL) { 123955373Smjacob /* 124055373Smjacob * There may be more than one CTIO for a data transfer, 124155373Smjacob * or this may be a status CTIO we're not monitoring. 124255373Smjacob * 124355373Smjacob * The assumption is that they'll all be returned in the 124455373Smjacob * order we got them. 124555373Smjacob */ 124674232Smjacob if (ct->ct_syshandle == 0) { 1247125187Smjacob if ((ct->ct_flags & CT2_SENDSTATUS) == 0) { 124864090Smjacob isp_prt(isp, pl, 124964090Smjacob "intermediate CTIO completed ok"); 125055373Smjacob } else { 125164090Smjacob isp_prt(isp, pl, 125264090Smjacob "unmonitored CTIO completed ok"); 125355373Smjacob } 125455373Smjacob } else { 125564090Smjacob isp_prt(isp, pl, 125664090Smjacob "NO xs for CTIO (handle 0x%x) status 0x%x", 125774232Smjacob ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); 125855373Smjacob } 125955373Smjacob } else { 126077365Smjacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 126177365Smjacob ISP_DMAFREE(isp, xs, ct->ct_syshandle); 126277365Smjacob } 1263125187Smjacob if (ct->ct_flags & CT2_SENDSTATUS) { 126455373Smjacob /* 126555373Smjacob * Sent status and command complete. 126655373Smjacob * 126755373Smjacob * We're now really done with this command, so we 126855373Smjacob * punt to the platform dependent layers because 126955373Smjacob * only there can we do the appropriate command 127055373Smjacob * complete thread synchronization. 127155373Smjacob */ 127264090Smjacob isp_prt(isp, pl, "status CTIO complete"); 127355373Smjacob } else { 127455373Smjacob /* 127555373Smjacob * Final CTIO completed. Release DMA resources and 127655373Smjacob * notify platform dependent layers. 127755373Smjacob */ 127864090Smjacob isp_prt(isp, pl, "data CTIO complete"); 127955373Smjacob } 128055373Smjacob (void) isp_async(isp, ISPASYNC_TARGET_ACTION, ct); 128155373Smjacob /* 128255373Smjacob * The platform layer will destroy the handle if appropriate. 128355373Smjacob */ 128455373Smjacob } 128555373Smjacob} 128655373Smjacob#endif 1287