1098ca2bdSWarner Losh /*- 22df76c16SMatt Jacob * Copyright (c) 1997-2009 by Matthew Jacob 3ea49c6e4SMatt Jacob * All rights reserved. 4ea49c6e4SMatt Jacob * 5ea49c6e4SMatt Jacob * Redistribution and use in source and binary forms, with or without 6ea49c6e4SMatt Jacob * modification, are permitted provided that the following conditions 7ea49c6e4SMatt Jacob * are met: 8ea49c6e4SMatt Jacob * 9e48b2487SMatt Jacob * 1. Redistributions of source code must retain the above copyright 10e48b2487SMatt Jacob * notice, this list of conditions and the following disclaimer. 11e48b2487SMatt Jacob * 2. Redistributions in binary form must reproduce the above copyright 12e48b2487SMatt Jacob * notice, this list of conditions and the following disclaimer in the 13e48b2487SMatt Jacob * documentation and/or other materials provided with the distribution. 14e48b2487SMatt Jacob * 15e48b2487SMatt Jacob * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16ea49c6e4SMatt Jacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17ea49c6e4SMatt Jacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e48b2487SMatt Jacob * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19e48b2487SMatt Jacob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20ea49c6e4SMatt Jacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21ea49c6e4SMatt Jacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22ea49c6e4SMatt Jacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23ea49c6e4SMatt Jacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24ea49c6e4SMatt Jacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25ea49c6e4SMatt Jacob * SUCH DAMAGE. 262df76c16SMatt Jacob * 27ea49c6e4SMatt Jacob */ 28ea49c6e4SMatt Jacob /* 29e48b2487SMatt Jacob * Machine and OS Independent Target Mode Code for the Qlogic SCSI/FC adapters. 30e48b2487SMatt Jacob */ 31e48b2487SMatt Jacob /* 3275c1e828SMatt Jacob * Bug fixes gratefully acknowledged from: 3375c1e828SMatt Jacob * Oded Kedem <oded@kashya.com> 3475c1e828SMatt Jacob */ 3575c1e828SMatt Jacob /* 36ea49c6e4SMatt Jacob * Include header file appropriate for platform we're building on. 37ea49c6e4SMatt Jacob */ 38ea49c6e4SMatt Jacob 39ea49c6e4SMatt Jacob #ifdef __NetBSD__ 40ea49c6e4SMatt Jacob #include <dev/ic/isp_netbsd.h> 41ea49c6e4SMatt Jacob #endif 42ea49c6e4SMatt Jacob #ifdef __FreeBSD__ 43799881e0SMatt Jacob #include <sys/cdefs.h> 44799881e0SMatt Jacob __FBSDID("$FreeBSD$"); 45ea49c6e4SMatt Jacob #include <dev/isp/isp_freebsd.h> 46ea49c6e4SMatt Jacob #endif 47ea49c6e4SMatt Jacob #ifdef __OpenBSD__ 48ea49c6e4SMatt Jacob #include <dev/ic/isp_openbsd.h> 49ea49c6e4SMatt Jacob #endif 50ea49c6e4SMatt Jacob #ifdef __linux__ 51ea49c6e4SMatt Jacob #include "isp_linux.h" 52ea49c6e4SMatt Jacob #endif 53ea49c6e4SMatt Jacob 54ea49c6e4SMatt Jacob #ifdef ISP_TARGET_MODE 55c5fd36edSAlexander Motin static const char atiocope[] = "ATIO returned for LUN %x because it was in the middle of Bus Device Reset on bus %d"; 56c5fd36edSAlexander Motin static const char atior[] = "ATIO returned for LUN %x from handle 0x%x because a Bus Reset occurred on bus %d"; 572df76c16SMatt Jacob static const char rqo[] = "%s: Request Queue Overflow"; 58ea49c6e4SMatt Jacob 599cd7268eSMatt Jacob static void isp_got_msg_fc(ispsoftc_t *, in_fcentry_t *); 6010365e5aSMatt Jacob static void isp_got_tmf_24xx(ispsoftc_t *, at7_entry_t *); 619cd7268eSMatt Jacob static void isp_handle_atio2(ispsoftc_t *, at2_entry_t *); 629cd7268eSMatt Jacob static void isp_handle_ctio2(ispsoftc_t *, ct2_entry_t *); 6310365e5aSMatt Jacob static void isp_handle_ctio7(ispsoftc_t *, ct7_entry_t *); 642df76c16SMatt Jacob static void isp_handle_24xx_inotify(ispsoftc_t *, in_fcentry_24xx_t *); 65ea49c6e4SMatt Jacob 66ea49c6e4SMatt Jacob /* 67ea49c6e4SMatt Jacob * The Qlogic driver gets an interrupt to look at response queue entries. 68ea49c6e4SMatt Jacob * Some of these are status completions for initiatior mode commands, but 69ea49c6e4SMatt Jacob * if target mode is enabled, we get a whole wad of response queue entries 70ea49c6e4SMatt Jacob * to be handled here. 71ea49c6e4SMatt Jacob * 72ea49c6e4SMatt Jacob * Basically the split into 3 main groups: Lun Enable/Modification responses, 73ea49c6e4SMatt Jacob * SCSI Command processing, and Immediate Notification events. 74ea49c6e4SMatt Jacob * 75ea49c6e4SMatt Jacob * You start by writing a request queue entry to enable target mode (and 76ea49c6e4SMatt Jacob * establish some resource limitations which you can modify later). 77ea49c6e4SMatt Jacob * The f/w responds with a LUN ENABLE or LUN MODIFY response with 78ea49c6e4SMatt Jacob * the status of this action. If the enable was successful, you can expect... 79ea49c6e4SMatt Jacob * 80ea49c6e4SMatt Jacob * Response queue entries with SCSI commands encapsulate show up in an ATIO 81ea49c6e4SMatt Jacob * (Accept Target IO) type- sometimes with enough info to stop the command at 82ea49c6e4SMatt Jacob * this level. Ultimately the driver has to feed back to the f/w's request 83ea49c6e4SMatt Jacob * queue a sequence of CTIOs (continue target I/O) that describe data to 84ea49c6e4SMatt Jacob * be moved and/or status to be sent) and finally finishing with sending 85ea49c6e4SMatt Jacob * to the f/w's response queue an ATIO which then completes the handshake 86ea49c6e4SMatt Jacob * with the f/w for that command. There's a lot of variations on this theme, 87ea49c6e4SMatt Jacob * including flags you can set in the CTIO for the Qlogic 2X00 fibre channel 88ea49c6e4SMatt Jacob * cards that 'auto-replenish' the f/w's ATIO count, but this is the basic 89ea49c6e4SMatt Jacob * gist of it. 90ea49c6e4SMatt Jacob * 91ea49c6e4SMatt Jacob * The third group that can show up in the response queue are Immediate 92ea49c6e4SMatt Jacob * Notification events. These include things like notifications of SCSI bus 93ea49c6e4SMatt Jacob * resets, or Bus Device Reset messages or other messages received. This 94f09deb69SJeroen Ruigrok van der Werven * a classic oddbins area. It can get a little weird because you then turn 95ea49c6e4SMatt Jacob * around and acknowledge the Immediate Notify by writing an entry onto the 96ea49c6e4SMatt Jacob * request queue and then the f/w turns around and gives you an acknowledgement 97ea49c6e4SMatt Jacob * to *your* acknowledgement on the response queue (the idea being to let 98ea49c6e4SMatt Jacob * the f/w tell you when the event is *really* over I guess). 99ea49c6e4SMatt Jacob * 100ea49c6e4SMatt Jacob */ 101ea49c6e4SMatt Jacob 102ea49c6e4SMatt Jacob 103ea49c6e4SMatt Jacob /* 104ea49c6e4SMatt Jacob * A new response queue entry has arrived. The interrupt service code 105ea49c6e4SMatt Jacob * has already swizzled it into the platform dependent from canonical form. 106ea49c6e4SMatt Jacob * 107ea49c6e4SMatt Jacob * Because of the way this driver is designed, unfortunately most of the 108ea49c6e4SMatt Jacob * actual synchronization work has to be done in the platform specific 109ea49c6e4SMatt Jacob * code- we have no synchroniation primitives in the common code. 110ea49c6e4SMatt Jacob */ 111ea49c6e4SMatt Jacob 112ea49c6e4SMatt Jacob int 11310365e5aSMatt Jacob isp_target_notify(ispsoftc_t *isp, void *vptr, uint32_t *optrp) 114ea49c6e4SMatt Jacob { 11510365e5aSMatt Jacob uint16_t status; 11610365e5aSMatt Jacob uint32_t seqid; 117ea49c6e4SMatt Jacob union { 118ea49c6e4SMatt Jacob at2_entry_t *at2iop; 119e5265237SMatt Jacob at2e_entry_t *at2eiop; 12010365e5aSMatt Jacob at7_entry_t *at7iop; 121ea49c6e4SMatt Jacob ct2_entry_t *ct2iop; 122e5265237SMatt Jacob ct2e_entry_t *ct2eiop; 12310365e5aSMatt Jacob ct7_entry_t *ct7iop; 124ea49c6e4SMatt Jacob lun_entry_t *lunenp; 125ea49c6e4SMatt Jacob in_fcentry_t *inot_fcp; 126e5265237SMatt Jacob in_fcentry_e_t *inote_fcp; 12710365e5aSMatt Jacob in_fcentry_24xx_t *inot_24xx; 128ea49c6e4SMatt Jacob na_fcentry_t *nack_fcp; 129e5265237SMatt Jacob na_fcentry_e_t *nacke_fcp; 13010365e5aSMatt Jacob na_fcentry_24xx_t *nack_24xx; 131ea49c6e4SMatt Jacob isphdr_t *hp; 13210365e5aSMatt Jacob abts_t *abts; 13310365e5aSMatt Jacob abts_rsp_t *abts_rsp; 13410365e5aSMatt Jacob els_t *els; 135ea49c6e4SMatt Jacob void * *vp; 136ea49c6e4SMatt Jacob #define at2iop unp.at2iop 137e5265237SMatt Jacob #define at2eiop unp.at2eiop 13810365e5aSMatt Jacob #define at7iop unp.at7iop 139ea49c6e4SMatt Jacob #define ct2iop unp.ct2iop 140e5265237SMatt Jacob #define ct2eiop unp.ct2eiop 14110365e5aSMatt Jacob #define ct7iop unp.ct7iop 142ea49c6e4SMatt Jacob #define lunenp unp.lunenp 143ea49c6e4SMatt Jacob #define inot_fcp unp.inot_fcp 144e5265237SMatt Jacob #define inote_fcp unp.inote_fcp 14510365e5aSMatt Jacob #define inot_24xx unp.inot_24xx 146ea49c6e4SMatt Jacob #define nack_fcp unp.nack_fcp 147e5265237SMatt Jacob #define nacke_fcp unp.nacke_fcp 14810365e5aSMatt Jacob #define nack_24xx unp.nack_24xx 14910365e5aSMatt Jacob #define abts unp.abts 15010365e5aSMatt Jacob #define abts_rsp unp.abts_rsp 15110365e5aSMatt Jacob #define els unp.els 152ea49c6e4SMatt Jacob #define hdrp unp.hp 153ea49c6e4SMatt Jacob } unp; 1541dae40ebSMatt Jacob uint8_t local[QENTRY_LEN]; 1552df76c16SMatt Jacob uint16_t iid; 1563e6deb33SAlexander Motin int bus, type, len, level, rval = 1; 1572df76c16SMatt Jacob isp_notify_t notify; 158ea49c6e4SMatt Jacob 1594fd13c1bSMatt Jacob type = isp_get_response_type(isp, (isphdr_t *)vptr); 160ea49c6e4SMatt Jacob unp.vp = vptr; 161ea49c6e4SMatt Jacob 162ea49c6e4SMatt Jacob ISP_TDQE(isp, "isp_target_notify", (int) *optrp, vptr); 163ea49c6e4SMatt Jacob 1644fd13c1bSMatt Jacob switch (type) { 165ea49c6e4SMatt Jacob case RQSTYPE_ATIO: 16610365e5aSMatt Jacob isp_get_atio7(isp, at7iop, (at7_entry_t *) local); 16710365e5aSMatt Jacob at7iop = (at7_entry_t *) local; 16810365e5aSMatt Jacob /* 1692df76c16SMatt Jacob * Check for and do something with commands whose 1702df76c16SMatt Jacob * IULEN extends past a single queue entry. 17110365e5aSMatt Jacob */ 172d2a2ccbcSAlexander Motin len = at7iop->at_ta_len & 0x0fff; 17310365e5aSMatt Jacob if (len > (QENTRY_LEN - 8)) { 17410365e5aSMatt Jacob len -= (QENTRY_LEN - 8); 1752df76c16SMatt Jacob isp_prt(isp, ISP_LOGINFO, "long IU length (%d) ignored", len); 17610365e5aSMatt Jacob while (len > 0) { 1772df76c16SMatt Jacob *optrp = ISP_NXT_QENTRY(*optrp, RESULT_QUEUE_LEN(isp)); 17810365e5aSMatt Jacob len -= QENTRY_LEN; 17910365e5aSMatt Jacob } 18010365e5aSMatt Jacob } 18110365e5aSMatt Jacob /* 18210365e5aSMatt Jacob * Check for a task management function 18310365e5aSMatt Jacob */ 18410365e5aSMatt Jacob if (at7iop->at_cmnd.fcp_cmnd_task_management) { 18510365e5aSMatt Jacob isp_got_tmf_24xx(isp, at7iop); 18610365e5aSMatt Jacob break; 18710365e5aSMatt Jacob } 18810365e5aSMatt Jacob /* 18910365e5aSMatt Jacob * Just go straight to outer layer for this one. 19010365e5aSMatt Jacob */ 1912df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_ACTION, local); 192ea49c6e4SMatt Jacob break; 19310365e5aSMatt Jacob 194ea49c6e4SMatt Jacob case RQSTYPE_ATIO2: 1952df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 196e5265237SMatt Jacob isp_get_atio2e(isp, at2eiop, (at2e_entry_t *) local); 19799ece8d6SMatt Jacob } else { 1984fd13c1bSMatt Jacob isp_get_atio2(isp, at2iop, (at2_entry_t *) local); 19999ece8d6SMatt Jacob } 2004fd13c1bSMatt Jacob isp_handle_atio2(isp, (at2_entry_t *) local); 201ea49c6e4SMatt Jacob break; 20210365e5aSMatt Jacob 203ac9d0a02SMatt Jacob case RQSTYPE_CTIO3: 204ea49c6e4SMatt Jacob case RQSTYPE_CTIO2: 2052df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 206e5265237SMatt Jacob isp_get_ctio2e(isp, ct2eiop, (ct2e_entry_t *) local); 20799ece8d6SMatt Jacob } else { 2084fd13c1bSMatt Jacob isp_get_ctio2(isp, ct2iop, (ct2_entry_t *) local); 20999ece8d6SMatt Jacob } 2104fd13c1bSMatt Jacob isp_handle_ctio2(isp, (ct2_entry_t *) local); 211ea49c6e4SMatt Jacob break; 21210365e5aSMatt Jacob 21310365e5aSMatt Jacob case RQSTYPE_CTIO7: 21410365e5aSMatt Jacob isp_get_ctio7(isp, ct7iop, (ct7_entry_t *) local); 21510365e5aSMatt Jacob isp_handle_ctio7(isp, (ct7_entry_t *) local); 21610365e5aSMatt Jacob break; 21710365e5aSMatt Jacob 218ea49c6e4SMatt Jacob case RQSTYPE_ENABLE_LUN: 219ea49c6e4SMatt Jacob case RQSTYPE_MODIFY_LUN: 2204fd13c1bSMatt Jacob isp_get_enable_lun(isp, lunenp, (lun_entry_t *) local); 2212df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_ACTION, local); 222ea49c6e4SMatt Jacob break; 223ea49c6e4SMatt Jacob 224ea49c6e4SMatt Jacob case RQSTYPE_NOTIFY: 22514a37293SMatt Jacob bus = 0; 22610365e5aSMatt Jacob if (IS_24XX(isp)) { 2272df76c16SMatt Jacob isp_get_notify_24xx(isp, inot_24xx, (in_fcentry_24xx_t *)local); 22810365e5aSMatt Jacob inot_24xx = (in_fcentry_24xx_t *) local; 2292df76c16SMatt Jacob isp_handle_24xx_inotify(isp, inot_24xx); 23010365e5aSMatt Jacob break; 2313e6deb33SAlexander Motin } else { 2322df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 2332df76c16SMatt Jacob in_fcentry_e_t *ecp = (in_fcentry_e_t *)local; 2342df76c16SMatt Jacob isp_get_notify_fc_e(isp, inote_fcp, ecp); 2352df76c16SMatt Jacob iid = ecp->in_iid; 2362df76c16SMatt Jacob status = ecp->in_status; 2372df76c16SMatt Jacob seqid = ecp->in_seqid; 23899ece8d6SMatt Jacob } else { 2392df76c16SMatt Jacob in_fcentry_t *fcp = (in_fcentry_t *)local; 2402df76c16SMatt Jacob isp_get_notify_fc(isp, inot_fcp, fcp); 2412df76c16SMatt Jacob iid = fcp->in_iid; 2422df76c16SMatt Jacob status = fcp->in_status; 2432df76c16SMatt Jacob seqid = fcp->in_seqid; 24499ece8d6SMatt Jacob } 24514a37293SMatt Jacob } 246b4110d46SMatt Jacob 2472df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "Immediate Notify On Bus %d, status=0x%x seqid=0x%x", bus, status, seqid); 24823ac1fceSMatt Jacob 249ea49c6e4SMatt Jacob switch (status) { 250ea49c6e4SMatt Jacob case IN_MSG_RECEIVED: 251ea49c6e4SMatt Jacob case IN_IDE_RECEIVED: 252e5265237SMatt Jacob isp_got_msg_fc(isp, (in_fcentry_t *)local); 253ea49c6e4SMatt Jacob break; 254ea49c6e4SMatt Jacob case IN_RSRC_UNAVAIL: 25510365e5aSMatt Jacob isp_prt(isp, ISP_LOGINFO, "Firmware out of ATIOs"); 256387d8239SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, local); 257e5265237SMatt Jacob break; 25810365e5aSMatt Jacob 2592df76c16SMatt Jacob case IN_RESET: 2602df76c16SMatt Jacob ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); 26110365e5aSMatt Jacob notify.nt_hba = isp; 2622df76c16SMatt Jacob notify.nt_wwn = INI_ANY; 2632df76c16SMatt Jacob notify.nt_tgt = TGT_ANY; 2642df76c16SMatt Jacob notify.nt_nphdl = iid; 2652df76c16SMatt Jacob notify.nt_sid = PORT_ANY; 2662df76c16SMatt Jacob notify.nt_did = PORT_ANY; 26710365e5aSMatt Jacob notify.nt_lun = LUN_ANY; 26810365e5aSMatt Jacob notify.nt_tagval = TAG_ANY; 2692df76c16SMatt Jacob notify.nt_tagval |= (((uint64_t)(isp->isp_serno++)) << 32); 27010365e5aSMatt Jacob notify.nt_ncode = NT_BUS_RESET; 27110365e5aSMatt Jacob notify.nt_need_ack = 1; 2722df76c16SMatt Jacob notify.nt_lreserved = local; 2732df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 274ea49c6e4SMatt Jacob break; 2752df76c16SMatt Jacob 276ea49c6e4SMatt Jacob case IN_PORT_LOGOUT: 2772df76c16SMatt Jacob ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); 2782df76c16SMatt Jacob notify.nt_hba = isp; 2792df76c16SMatt Jacob notify.nt_wwn = INI_ANY; 2802df76c16SMatt Jacob notify.nt_nphdl = iid; 2812df76c16SMatt Jacob notify.nt_sid = PORT_ANY; 2822df76c16SMatt Jacob notify.nt_did = PORT_ANY; 2832df76c16SMatt Jacob notify.nt_ncode = NT_LOGOUT; 2842df76c16SMatt Jacob notify.nt_need_ack = 1; 2852df76c16SMatt Jacob notify.nt_lreserved = local; 2862df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 287ea49c6e4SMatt Jacob break; 2882df76c16SMatt Jacob 2892df76c16SMatt Jacob case IN_ABORT_TASK: 2902df76c16SMatt Jacob ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); 2912df76c16SMatt Jacob notify.nt_hba = isp; 2922df76c16SMatt Jacob notify.nt_wwn = INI_ANY; 2932df76c16SMatt Jacob notify.nt_nphdl = iid; 2942df76c16SMatt Jacob notify.nt_sid = PORT_ANY; 2952df76c16SMatt Jacob notify.nt_did = PORT_ANY; 2962df76c16SMatt Jacob notify.nt_ncode = NT_ABORT_TASK; 2972df76c16SMatt Jacob notify.nt_need_ack = 1; 2982df76c16SMatt Jacob notify.nt_lreserved = local; 2992df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 3002df76c16SMatt Jacob break; 3012df76c16SMatt Jacob 3022df76c16SMatt Jacob case IN_GLOBAL_LOGO: 3032df76c16SMatt Jacob isp_prt(isp, ISP_LOGTINFO, "%s: all ports logged out", __func__); 3042df76c16SMatt Jacob ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); 3052df76c16SMatt Jacob notify.nt_hba = isp; 3062df76c16SMatt Jacob notify.nt_wwn = INI_ANY; 3072df76c16SMatt Jacob notify.nt_nphdl = NIL_HANDLE; 3082df76c16SMatt Jacob notify.nt_sid = PORT_ANY; 3092df76c16SMatt Jacob notify.nt_did = PORT_ANY; 3102df76c16SMatt Jacob notify.nt_ncode = NT_GLOBAL_LOGOUT; 311387d8239SMatt Jacob notify.nt_need_ack = 1; 312387d8239SMatt Jacob notify.nt_lreserved = local; 3132df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 3142df76c16SMatt Jacob break; 3152df76c16SMatt Jacob 3162df76c16SMatt Jacob case IN_PORT_CHANGED: 3172df76c16SMatt Jacob isp_prt(isp, ISP_LOGTINFO, "%s: port changed", __func__); 318387d8239SMatt Jacob ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); 319387d8239SMatt Jacob notify.nt_hba = isp; 320387d8239SMatt Jacob notify.nt_wwn = INI_ANY; 321387d8239SMatt Jacob notify.nt_nphdl = NIL_HANDLE; 322387d8239SMatt Jacob notify.nt_sid = PORT_ANY; 323387d8239SMatt Jacob notify.nt_did = PORT_ANY; 324387d8239SMatt Jacob notify.nt_ncode = NT_CHANGED; 325387d8239SMatt Jacob notify.nt_need_ack = 1; 326387d8239SMatt Jacob notify.nt_lreserved = local; 327387d8239SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 3282df76c16SMatt Jacob break; 3292df76c16SMatt Jacob 330ea49c6e4SMatt Jacob default: 3312df76c16SMatt Jacob ISP_SNPRINTF(local, sizeof local, "%s: unknown status to RQSTYPE_NOTIFY (0x%x)", __func__, status); 3322df76c16SMatt Jacob isp_print_bytes(isp, local, QENTRY_LEN, vptr); 333387d8239SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, local); 334ea49c6e4SMatt Jacob break; 335ea49c6e4SMatt Jacob } 336ea49c6e4SMatt Jacob break; 337ea49c6e4SMatt Jacob 338ea49c6e4SMatt Jacob case RQSTYPE_NOTIFY_ACK: 339ea49c6e4SMatt Jacob /* 340ea49c6e4SMatt Jacob * The ISP is acknowledging our acknowledgement of an 341ea49c6e4SMatt Jacob * Immediate Notify entry for some asynchronous event. 342ea49c6e4SMatt Jacob */ 34310365e5aSMatt Jacob if (IS_24XX(isp)) { 3442df76c16SMatt Jacob isp_get_notify_ack_24xx(isp, nack_24xx, (na_fcentry_24xx_t *) local); 34510365e5aSMatt Jacob nack_24xx = (na_fcentry_24xx_t *) local; 34610365e5aSMatt Jacob if (nack_24xx->na_status != NA_OK) { 34710365e5aSMatt Jacob level = ISP_LOGINFO; 34810365e5aSMatt Jacob } else { 34910365e5aSMatt Jacob level = ISP_LOGTDEBUG1; 35010365e5aSMatt Jacob } 3512df76c16SMatt Jacob isp_prt(isp, level, "Notify Ack Status=0x%x; Subcode 0x%x seqid=0x%x", nack_24xx->na_status, nack_24xx->na_status_subcode, nack_24xx->na_rxid); 3523e6deb33SAlexander Motin } else { 3532df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 3542df76c16SMatt Jacob isp_get_notify_ack_fc_e(isp, nacke_fcp, (na_fcentry_e_t *)local); 35599ece8d6SMatt Jacob } else { 3562df76c16SMatt Jacob isp_get_notify_ack_fc(isp, nack_fcp, (na_fcentry_t *)local); 35799ece8d6SMatt Jacob } 3584fd13c1bSMatt Jacob nack_fcp = (na_fcentry_t *)local; 35910365e5aSMatt Jacob if (nack_fcp->na_status != NA_OK) { 36010365e5aSMatt Jacob level = ISP_LOGINFO; 36110365e5aSMatt Jacob } else { 36210365e5aSMatt Jacob level = ISP_LOGTDEBUG1; 36310365e5aSMatt Jacob } 3642df76c16SMatt Jacob isp_prt(isp, level, "Notify Ack Status=0x%x seqid 0x%x", nack_fcp->na_status, nack_fcp->na_seqid); 365ea49c6e4SMatt Jacob } 366ea49c6e4SMatt Jacob break; 36710365e5aSMatt Jacob 36810365e5aSMatt Jacob case RQSTYPE_ABTS_RCVD: 36910365e5aSMatt Jacob isp_get_abts(isp, abts, (abts_t *)local); 3702df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_ACTION, &local); 37110365e5aSMatt Jacob break; 37210365e5aSMatt Jacob case RQSTYPE_ABTS_RSP: 37310365e5aSMatt Jacob isp_get_abts_rsp(isp, abts_rsp, (abts_rsp_t *)local); 37410365e5aSMatt Jacob abts_rsp = (abts_rsp_t *) local; 37510365e5aSMatt Jacob if (abts_rsp->abts_rsp_status) { 37610365e5aSMatt Jacob level = ISP_LOGINFO; 37710365e5aSMatt Jacob } else { 37810365e5aSMatt Jacob level = ISP_LOGTDEBUG0; 37910365e5aSMatt Jacob } 3802df76c16SMatt Jacob isp_prt(isp, level, "ABTS RSP response[0x%x]: status=0x%x sub=(0x%x 0x%x)", abts_rsp->abts_rsp_rxid_task, abts_rsp->abts_rsp_status, 3812df76c16SMatt Jacob abts_rsp->abts_rsp_payload.rsp.subcode1, abts_rsp->abts_rsp_payload.rsp.subcode2); 38210365e5aSMatt Jacob break; 383ea49c6e4SMatt Jacob default: 3842df76c16SMatt Jacob isp_prt(isp, ISP_LOGERR, "%s: unknown entry type 0x%x", __func__, type); 385e63442b6SMatt Jacob rval = 0; 386ea49c6e4SMatt Jacob break; 387ea49c6e4SMatt Jacob } 388ea49c6e4SMatt Jacob #undef atiop 389ea49c6e4SMatt Jacob #undef at2iop 390e5265237SMatt Jacob #undef at2eiop 39110365e5aSMatt Jacob #undef at7iop 392ea49c6e4SMatt Jacob #undef ctiop 393ea49c6e4SMatt Jacob #undef ct2iop 394e5265237SMatt Jacob #undef ct2eiop 39510365e5aSMatt Jacob #undef ct7iop 396ea49c6e4SMatt Jacob #undef lunenp 397ea49c6e4SMatt Jacob #undef inotp 398ea49c6e4SMatt Jacob #undef inot_fcp 399e5265237SMatt Jacob #undef inote_fcp 40010365e5aSMatt Jacob #undef inot_24xx 401ea49c6e4SMatt Jacob #undef nackp 402ea49c6e4SMatt Jacob #undef nack_fcp 403e5265237SMatt Jacob #undef nacke_fcp 40410365e5aSMatt Jacob #undef hack_24xx 40510365e5aSMatt Jacob #undef abts 40610365e5aSMatt Jacob #undef abts_rsp 40710365e5aSMatt Jacob #undef els 408ea49c6e4SMatt Jacob #undef hdrp 409ea49c6e4SMatt Jacob return (rval); 410ea49c6e4SMatt Jacob } 411ea49c6e4SMatt Jacob 412ea49c6e4SMatt Jacob int 4139cd7268eSMatt Jacob isp_target_put_entry(ispsoftc_t *isp, void *ap) 414ea49c6e4SMatt Jacob { 415ea49c6e4SMatt Jacob void *outp; 4161dae40ebSMatt Jacob uint8_t etype = ((isphdr_t *) ap)->rqs_entry_type; 417ea49c6e4SMatt Jacob 4182df76c16SMatt Jacob outp = isp_getrqentry(isp); 4192df76c16SMatt Jacob if (outp == NULL) { 4202df76c16SMatt Jacob isp_prt(isp, ISP_LOGWARN, rqo, __func__); 421ea49c6e4SMatt Jacob return (-1); 422ea49c6e4SMatt Jacob } 423ea49c6e4SMatt Jacob switch (etype) { 424ea49c6e4SMatt Jacob case RQSTYPE_ATIO2: 4252df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 4262df76c16SMatt Jacob isp_put_atio2e(isp, (at2e_entry_t *) ap, (at2e_entry_t *) outp); 42799ece8d6SMatt Jacob } else { 4282df76c16SMatt Jacob isp_put_atio2(isp, (at2_entry_t *) ap, (at2_entry_t *) outp); 42999ece8d6SMatt Jacob } 430ea49c6e4SMatt Jacob break; 431ea49c6e4SMatt Jacob case RQSTYPE_CTIO2: 4322df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 4332df76c16SMatt Jacob isp_put_ctio2e(isp, (ct2e_entry_t *) ap, (ct2e_entry_t *) outp); 43499ece8d6SMatt Jacob } else { 4352df76c16SMatt Jacob isp_put_ctio2(isp, (ct2_entry_t *) ap, (ct2_entry_t *) outp); 43699ece8d6SMatt Jacob } 437ea49c6e4SMatt Jacob break; 43810365e5aSMatt Jacob case RQSTYPE_CTIO7: 43910365e5aSMatt Jacob isp_put_ctio7(isp, (ct7_entry_t *) ap, (ct7_entry_t *) outp); 44010365e5aSMatt Jacob break; 441ea49c6e4SMatt Jacob default: 4422df76c16SMatt Jacob isp_prt(isp, ISP_LOGERR, "%s: Unknown type 0x%x", __func__, etype); 443ea49c6e4SMatt Jacob return (-1); 444ea49c6e4SMatt Jacob } 4452df76c16SMatt Jacob ISP_TDQE(isp, __func__, isp->isp_reqidx, ap); 4462df76c16SMatt Jacob ISP_SYNC_REQUEST(isp); 447ea49c6e4SMatt Jacob return (0); 448ea49c6e4SMatt Jacob } 449ea49c6e4SMatt Jacob 450ea49c6e4SMatt Jacob int 4519cd7268eSMatt Jacob isp_target_put_atio(ispsoftc_t *isp, void *arg) 452ea49c6e4SMatt Jacob { 4533e6deb33SAlexander Motin at2_entry_t *aep = arg; 454ea49c6e4SMatt Jacob union { 455ea49c6e4SMatt Jacob at2_entry_t _atio2; 456e5265237SMatt Jacob at2e_entry_t _atio2e; 457ea49c6e4SMatt Jacob } atun; 458ea49c6e4SMatt Jacob 4592df76c16SMatt Jacob ISP_MEMZERO(&atun, sizeof atun); 460ea49c6e4SMatt Jacob atun._atio2.at_header.rqs_entry_type = RQSTYPE_ATIO2; 461ea49c6e4SMatt Jacob atun._atio2.at_header.rqs_entry_count = 1; 4622df76c16SMatt Jacob if (ISP_CAP_SCCFW(isp)) { 46310365e5aSMatt Jacob atun._atio2.at_scclun = aep->at_scclun; 4642133e16fSMatt Jacob } else { 4651dae40ebSMatt Jacob atun._atio2.at_lun = (uint8_t) aep->at_lun; 4662133e16fSMatt Jacob } 4672df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 468e5265237SMatt Jacob atun._atio2e.at_iid = ((at2e_entry_t *)aep)->at_iid; 469e5265237SMatt Jacob } else { 47003cf2fbaSMatt Jacob atun._atio2.at_iid = aep->at_iid; 471e5265237SMatt Jacob } 472e5824c5dSMatt Jacob atun._atio2.at_rxid = aep->at_rxid; 473ea49c6e4SMatt Jacob atun._atio2.at_status = CT_OK; 474ea49c6e4SMatt Jacob return (isp_target_put_entry(isp, &atun)); 475ea49c6e4SMatt Jacob } 476ea49c6e4SMatt Jacob 477ea49c6e4SMatt Jacob /* 478ea49c6e4SMatt Jacob * Command completion- both for handling cases of no resources or 479ea49c6e4SMatt Jacob * no blackhole driver, or other cases where we have to, inline, 480ea49c6e4SMatt Jacob * finish the command sanely, or for normal command completion. 481ea49c6e4SMatt Jacob * 482ea49c6e4SMatt Jacob * The 'completion' code value has the scsi status byte in the low 8 bits. 483ea49c6e4SMatt Jacob * If status is a CHECK CONDITION and bit 8 is nonzero, then bits 12..15 have 484ea49c6e4SMatt Jacob * the sense key and bits 16..23 have the ASCQ and bits 24..31 have the ASC 485ea49c6e4SMatt Jacob * values. 486ea49c6e4SMatt Jacob * 487ea49c6e4SMatt Jacob * NB: the key, asc, ascq, cannot be used for parallel SCSI as it doesn't 488b25bcef8SMatt Jacob * NB: inline SCSI sense reporting. As such, we lose this information. XXX. 489ea49c6e4SMatt Jacob * 490ea49c6e4SMatt Jacob * For both parallel && fibre channel, we use the feature that does 491ea49c6e4SMatt Jacob * an automatic resource autoreplenish so we don't have then later do 492ea49c6e4SMatt Jacob * put of an atio to replenish the f/w's resource count. 493ea49c6e4SMatt Jacob */ 494ea49c6e4SMatt Jacob 495ea49c6e4SMatt Jacob int 4962df76c16SMatt Jacob isp_endcmd(ispsoftc_t *isp, ...) 497ea49c6e4SMatt Jacob { 4982df76c16SMatt Jacob uint32_t code, hdl; 4992df76c16SMatt Jacob uint8_t sts; 500ea49c6e4SMatt Jacob union { 501ea49c6e4SMatt Jacob ct2_entry_t _ctio2; 502e5265237SMatt Jacob ct2e_entry_t _ctio2e; 50310365e5aSMatt Jacob ct7_entry_t _ctio7; 504ea49c6e4SMatt Jacob } un; 5052df76c16SMatt Jacob va_list ap; 5068290ea90SAlexander Motin int vpidx, nphdl; 507ea49c6e4SMatt Jacob 5082df76c16SMatt Jacob ISP_MEMZERO(&un, sizeof un); 509ea49c6e4SMatt Jacob 51010365e5aSMatt Jacob if (IS_24XX(isp)) { 5112df76c16SMatt Jacob at7_entry_t *aep; 51210365e5aSMatt Jacob ct7_entry_t *cto = &un._ctio7; 51310365e5aSMatt Jacob 5142df76c16SMatt Jacob va_start(ap, isp); 5152df76c16SMatt Jacob aep = va_arg(ap, at7_entry_t *); 5162df76c16SMatt Jacob nphdl = va_arg(ap, int); 5172df76c16SMatt Jacob /* 5182df76c16SMatt Jacob * Note that vpidx may equal 0xff (unknown) here 5192df76c16SMatt Jacob */ 5202df76c16SMatt Jacob vpidx = va_arg(ap, int); 5212df76c16SMatt Jacob code = va_arg(ap, uint32_t); 5222df76c16SMatt Jacob hdl = va_arg(ap, uint32_t); 5232df76c16SMatt Jacob va_end(ap); 5242df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: [RX_ID 0x%x] chan %d code %x", __func__, aep->at_rxid, vpidx, code); 5252df76c16SMatt Jacob 5262df76c16SMatt Jacob sts = code & 0xff; 52710365e5aSMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO7; 52810365e5aSMatt Jacob cto->ct_header.rqs_entry_count = 1; 5292df76c16SMatt Jacob cto->ct_nphdl = nphdl; 53010365e5aSMatt Jacob cto->ct_rxid = aep->at_rxid; 5312df76c16SMatt Jacob cto->ct_iid_lo = (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2]; 53210365e5aSMatt Jacob cto->ct_iid_hi = aep->at_hdr.s_id[0]; 53310365e5aSMatt Jacob cto->ct_oxid = aep->at_hdr.ox_id; 53410365e5aSMatt Jacob cto->ct_scsi_status = sts; 5352df76c16SMatt Jacob cto->ct_vpidx = vpidx; 5362df76c16SMatt Jacob cto->ct_flags = CT7_NOACK; 5372df76c16SMatt Jacob if (code & ECMD_TERMINATE) { 5382df76c16SMatt Jacob cto->ct_flags |= CT7_TERMINATE; 5392df76c16SMatt Jacob } else if (code & ECMD_SVALID) { 5402df76c16SMatt Jacob cto->ct_flags |= CT7_FLAG_MODE1 | CT7_SENDSTATUS; 5412df76c16SMatt Jacob cto->ct_scsi_status |= (FCP_SNSLEN_VALID << 8); 542352427b3SAlexander Motin cto->ct_senselen = min(16, MAXRESPLEN_24XX); 5432df76c16SMatt Jacob ISP_MEMZERO(cto->rsp.m1.ct_resp, sizeof (cto->rsp.m1.ct_resp)); 54410365e5aSMatt Jacob cto->rsp.m1.ct_resp[0] = 0xf0; 54510365e5aSMatt Jacob cto->rsp.m1.ct_resp[2] = (code >> 12) & 0xf; 54610365e5aSMatt Jacob cto->rsp.m1.ct_resp[7] = 8; 547387d8239SMatt Jacob cto->rsp.m1.ct_resp[12] = (code >> 16) & 0xff; 548387d8239SMatt Jacob cto->rsp.m1.ct_resp[13] = (code >> 24) & 0xff; 549352427b3SAlexander Motin } else if (code & ECMD_RVALID) { 550352427b3SAlexander Motin cto->ct_flags |= CT7_FLAG_MODE1 | CT7_SENDSTATUS; 551352427b3SAlexander Motin cto->ct_scsi_status |= (FCP_RSPLEN_VALID << 8); 552352427b3SAlexander Motin cto->rsp.m1.ct_resplen = 4; 553352427b3SAlexander Motin ISP_MEMZERO(cto->rsp.m1.ct_resp, sizeof (cto->rsp.m1.ct_resp)); 554352427b3SAlexander Motin cto->rsp.m1.ct_resp[0] = (code >> 12) & 0xf; 555352427b3SAlexander Motin cto->rsp.m1.ct_resp[1] = (code >> 16) & 0xff; 556352427b3SAlexander Motin cto->rsp.m1.ct_resp[2] = (code >> 24) & 0xff; 557352427b3SAlexander Motin cto->rsp.m1.ct_resp[3] = 0; 5582df76c16SMatt Jacob } else { 5592df76c16SMatt Jacob cto->ct_flags |= CT7_FLAG_MODE1 | CT7_SENDSTATUS; 56010365e5aSMatt Jacob } 561*a6036a44SAlexander Motin if (aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl != 0) { 56210365e5aSMatt Jacob cto->ct_resid = aep->at_cmnd.cdb_dl.sf.fcp_cmnd_dl; 5632df76c16SMatt Jacob cto->ct_scsi_status |= (FCP_RESID_UNDERFLOW << 8); 5642df76c16SMatt Jacob } 56510365e5aSMatt Jacob cto->ct_syshandle = hdl; 5663e6deb33SAlexander Motin } else { 5672df76c16SMatt Jacob at2_entry_t *aep; 568ea49c6e4SMatt Jacob ct2_entry_t *cto = &un._ctio2; 569ea49c6e4SMatt Jacob 5702df76c16SMatt Jacob va_start(ap, isp); 5712df76c16SMatt Jacob aep = va_arg(ap, at2_entry_t *); 5728290ea90SAlexander Motin /* nphdl and vpidx are unused here. */ 5738290ea90SAlexander Motin nphdl = va_arg(ap, int); 5748290ea90SAlexander Motin vpidx = va_arg(ap, int); 5752df76c16SMatt Jacob code = va_arg(ap, uint32_t); 5762df76c16SMatt Jacob hdl = va_arg(ap, uint32_t); 5772df76c16SMatt Jacob va_end(ap); 5782df76c16SMatt Jacob 5792df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: [RX_ID 0x%x] code %x", __func__, aep->at_rxid, code); 5802df76c16SMatt Jacob 5812df76c16SMatt Jacob sts = code & 0xff; 582ea49c6e4SMatt Jacob cto->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 583ea49c6e4SMatt Jacob cto->ct_header.rqs_entry_count = 1; 5842df76c16SMatt Jacob if (ISP_CAP_SCCFW(isp) == 0) { 585ea49c6e4SMatt Jacob cto->ct_lun = aep->at_lun; 5862133e16fSMatt Jacob } 5872df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 588e5265237SMatt Jacob un._ctio2e.ct_iid = ((at2e_entry_t *)aep)->at_iid; 589e5265237SMatt Jacob } else { 590e5265237SMatt Jacob cto->ct_iid = aep->at_iid; 591e5265237SMatt Jacob } 592ea49c6e4SMatt Jacob cto->ct_rxid = aep->at_rxid; 593eedb2dfeSMatt Jacob cto->rsp.m1.ct_scsi_status = sts; 594ea49c6e4SMatt Jacob cto->ct_flags = CT2_SENDSTATUS | CT2_NO_DATA | CT2_FLAG_MODE1; 595ea49c6e4SMatt Jacob if (hdl == 0) { 596ea49c6e4SMatt Jacob cto->ct_flags |= CT2_CCINCR; 597ea49c6e4SMatt Jacob } 598ea49c6e4SMatt Jacob if (aep->at_datalen) { 599ea49c6e4SMatt Jacob cto->ct_resid = aep->at_datalen; 6005d571944SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_DATA_UNDER; 601ea49c6e4SMatt Jacob } 602eedb2dfeSMatt Jacob if (sts == SCSI_CHECK && (code & ECMD_SVALID)) { 603ea49c6e4SMatt Jacob cto->rsp.m1.ct_resp[0] = 0xf0; 604ea49c6e4SMatt Jacob cto->rsp.m1.ct_resp[2] = (code >> 12) & 0xf; 605ea49c6e4SMatt Jacob cto->rsp.m1.ct_resp[7] = 8; 606ea49c6e4SMatt Jacob cto->rsp.m1.ct_resp[12] = (code >> 24) & 0xff; 607ea49c6e4SMatt Jacob cto->rsp.m1.ct_resp[13] = (code >> 16) & 0xff; 608ea49c6e4SMatt Jacob cto->rsp.m1.ct_senselen = 16; 6095d571944SMatt Jacob cto->rsp.m1.ct_scsi_status |= CT2_SNSLEN_VALID; 610ea49c6e4SMatt Jacob } 611b0bd9b71SMatt Jacob cto->ct_syshandle = hdl; 612ea49c6e4SMatt Jacob } 613ea49c6e4SMatt Jacob return (isp_target_put_entry(isp, &un)); 614ea49c6e4SMatt Jacob } 615ea49c6e4SMatt Jacob 6169cd7268eSMatt Jacob /* 6179cd7268eSMatt Jacob * These are either broadcast events or specifically CTIO fast completion 6189cd7268eSMatt Jacob */ 6192df76c16SMatt Jacob 620e63442b6SMatt Jacob int 6219cd7268eSMatt Jacob isp_target_async(ispsoftc_t *isp, int bus, int event) 622ea49c6e4SMatt Jacob { 6232df76c16SMatt Jacob isp_notify_t notify; 624e5265237SMatt Jacob 6252df76c16SMatt Jacob ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); 626e5265237SMatt Jacob notify.nt_hba = isp; 6272df76c16SMatt Jacob notify.nt_wwn = INI_ANY; 6282df76c16SMatt Jacob notify.nt_nphdl = NIL_HANDLE; 6292df76c16SMatt Jacob notify.nt_sid = PORT_ANY; 6302df76c16SMatt Jacob notify.nt_did = PORT_ANY; 6312df76c16SMatt Jacob notify.nt_tgt = TGT_ANY; 6322df76c16SMatt Jacob notify.nt_channel = bus; 633e5265237SMatt Jacob notify.nt_lun = LUN_ANY; 634e5265237SMatt Jacob notify.nt_tagval = TAG_ANY; 6352df76c16SMatt Jacob notify.nt_tagval |= (((uint64_t)(isp->isp_serno++)) << 32); 636ea49c6e4SMatt Jacob 637ea49c6e4SMatt Jacob switch (event) { 638e5265237SMatt Jacob case ASYNC_LOOP_UP: 639e5265237SMatt Jacob case ASYNC_PTPMODE: 6402df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: LOOP UP", __func__); 641e5265237SMatt Jacob notify.nt_ncode = NT_LINK_UP; 6422df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 643e5265237SMatt Jacob break; 644e5265237SMatt Jacob case ASYNC_LOOP_DOWN: 6452df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: LOOP DOWN", __func__); 646e5265237SMatt Jacob notify.nt_ncode = NT_LINK_DOWN; 6472df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 648e5265237SMatt Jacob break; 64910365e5aSMatt Jacob case ASYNC_LIP_ERROR: 650e2929f5fSAlexander Motin case ASYNC_LIP_NOS_OLS_RECV: 651ea49c6e4SMatt Jacob case ASYNC_LIP_OCCURRED: 65223ac1fceSMatt Jacob case ASYNC_LOOP_RESET: 6532df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: LIP RESET", __func__); 654e5265237SMatt Jacob notify.nt_ncode = NT_LIP_RESET; 6552df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 656e5265237SMatt Jacob break; 657ea49c6e4SMatt Jacob case ASYNC_BUS_RESET: 658e5265237SMatt Jacob case ASYNC_TIMEOUT_RESET: /* XXX: where does this come from ? */ 6592df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: BUS RESET", __func__); 660e5265237SMatt Jacob notify.nt_ncode = NT_BUS_RESET; 6612df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 662ea49c6e4SMatt Jacob break; 663ea49c6e4SMatt Jacob case ASYNC_DEVICE_RESET: 6642df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: DEVICE RESET", __func__); 665e5265237SMatt Jacob notify.nt_ncode = NT_TARGET_RESET; 6662df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 667ea49c6e4SMatt Jacob break; 6682f9e7606SMatt Jacob case ASYNC_CTIO_DONE: 669e5265237SMatt Jacob { 670e5265237SMatt Jacob uint8_t storage[QENTRY_LEN]; 6712df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "%s: CTIO DONE", __func__); 672e5265237SMatt Jacob memset(storage, 0, QENTRY_LEN); 67310365e5aSMatt Jacob if (IS_24XX(isp)) { 67410365e5aSMatt Jacob ct7_entry_t *ct = (ct7_entry_t *) storage; 67510365e5aSMatt Jacob ct->ct_header.rqs_entry_type = RQSTYPE_CTIO7; 67610365e5aSMatt Jacob ct->ct_nphdl = CT7_OK; 67710365e5aSMatt Jacob ct->ct_syshandle = bus; 6782df76c16SMatt Jacob ct->ct_flags = CT7_SENDSTATUS; 6793e6deb33SAlexander Motin } else { 68099ece8d6SMatt Jacob /* This should also suffice for 2K login code */ 681e5265237SMatt Jacob ct2_entry_t *ct = (ct2_entry_t *) storage; 682e5265237SMatt Jacob ct->ct_header.rqs_entry_type = RQSTYPE_CTIO2; 683e5265237SMatt Jacob ct->ct_status = CT_OK; 684e5265237SMatt Jacob ct->ct_syshandle = bus; 685e5265237SMatt Jacob ct->ct_flags = CT2_SENDSTATUS|CT2_FASTPOST; 686e5265237SMatt Jacob } 6872df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_ACTION, storage); 68810365e5aSMatt Jacob break; 689e5265237SMatt Jacob } 690ea49c6e4SMatt Jacob default: 6912df76c16SMatt Jacob isp_prt(isp, ISP_LOGERR, "%s: unknown event 0x%x", __func__, event); 692e5265237SMatt Jacob if (isp->isp_state == ISP_RUNSTATE) { 693387d8239SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, NULL); 694e5265237SMatt Jacob } 695ea49c6e4SMatt Jacob break; 696ea49c6e4SMatt Jacob } 697e63442b6SMatt Jacob return (0); 698ea49c6e4SMatt Jacob } 699ea49c6e4SMatt Jacob 700ea49c6e4SMatt Jacob /* 701ea49c6e4SMatt Jacob * Synthesize a message from the task management flags in a FCP_CMND_IU. 702ea49c6e4SMatt Jacob */ 703ea49c6e4SMatt Jacob static void 7049cd7268eSMatt Jacob isp_got_msg_fc(ispsoftc_t *isp, in_fcentry_t *inp) 705ea49c6e4SMatt Jacob { 7062df76c16SMatt Jacob isp_notify_t notify; 707c5fd36edSAlexander Motin static const char f1[] = "%s from N-port handle 0x%x lun %x seq 0x%x"; 708c5fd36edSAlexander Motin static const char f2[] = "unknown %s 0x%x lun %x N-Port handle 0x%x task flags 0x%x seq 0x%x\n"; 709c5fd36edSAlexander Motin uint16_t seqid, nphdl; 710ea49c6e4SMatt Jacob 7112df76c16SMatt Jacob ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); 7122df76c16SMatt Jacob notify.nt_hba = isp; 7132df76c16SMatt Jacob notify.nt_wwn = INI_ANY; 7142df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 7152df76c16SMatt Jacob notify.nt_nphdl = ((in_fcentry_e_t *)inp)->in_iid; 716c5fd36edSAlexander Motin nphdl = ((in_fcentry_e_t *)inp)->in_iid; 7179cd7268eSMatt Jacob seqid = ((in_fcentry_e_t *)inp)->in_seqid; 718d82b6503SMatt Jacob } else { 7192df76c16SMatt Jacob notify.nt_nphdl = inp->in_iid; 720c5fd36edSAlexander Motin nphdl = inp->in_iid; 7219cd7268eSMatt Jacob seqid = inp->in_seqid; 722d82b6503SMatt Jacob } 7232df76c16SMatt Jacob notify.nt_sid = PORT_ANY; 7242df76c16SMatt Jacob notify.nt_did = PORT_ANY; 7252df76c16SMatt Jacob 726e5265237SMatt Jacob /* nt_tgt set in outer layers */ 7272df76c16SMatt Jacob if (ISP_CAP_SCCFW(isp)) { 7282df76c16SMatt Jacob notify.nt_lun = inp->in_scclun; 7296af11b82SAlexander Motin #if __FreeBSD_version < 1000700 7306af11b82SAlexander Motin notify.nt_lun &= 0x3fff; 7316af11b82SAlexander Motin #endif 732e5265237SMatt Jacob } else { 7332df76c16SMatt Jacob notify.nt_lun = inp->in_lun; 734e5265237SMatt Jacob } 7352df76c16SMatt Jacob notify.nt_tagval = seqid; 7362df76c16SMatt Jacob notify.nt_tagval |= (((uint64_t)(isp->isp_serno++)) << 32); 7372df76c16SMatt Jacob notify.nt_need_ack = 1; 7382df76c16SMatt Jacob notify.nt_lreserved = inp; 739d82b6503SMatt Jacob 740ea49c6e4SMatt Jacob if (inp->in_status != IN_MSG_RECEIVED) { 741c5fd36edSAlexander Motin isp_prt(isp, ISP_LOGINFO, f2, "immediate notify status", inp->in_status, notify.nt_lun, nphdl, inp->in_task_flags, inp->in_seqid); 742387d8239SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inp); 743e5265237SMatt Jacob return; 744e5265237SMatt Jacob } 745ea49c6e4SMatt Jacob 7462f9e7606SMatt Jacob if (inp->in_task_flags & TASK_FLAGS_ABORT_TASK_SET) { 747c5fd36edSAlexander Motin isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK SET", nphdl, notify.nt_lun, inp->in_seqid); 7482df76c16SMatt Jacob notify.nt_ncode = NT_ABORT_TASK_SET; 749ea49c6e4SMatt Jacob } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_TASK_SET) { 750c5fd36edSAlexander Motin isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET", nphdl, notify.nt_lun, inp->in_seqid); 7512df76c16SMatt Jacob notify.nt_ncode = NT_CLEAR_TASK_SET; 7522f9e7606SMatt Jacob } else if (inp->in_task_flags & TASK_FLAGS_LUN_RESET) { 753c5fd36edSAlexander Motin isp_prt(isp, ISP_LOGINFO, f1, "LUN RESET", nphdl, notify.nt_lun, inp->in_seqid); 7542df76c16SMatt Jacob notify.nt_ncode = NT_LUN_RESET; 755ea49c6e4SMatt Jacob } else if (inp->in_task_flags & TASK_FLAGS_TARGET_RESET) { 756c5fd36edSAlexander Motin isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET", nphdl, notify.nt_lun, inp->in_seqid); 7572df76c16SMatt Jacob notify.nt_ncode = NT_TARGET_RESET; 758ea49c6e4SMatt Jacob } else if (inp->in_task_flags & TASK_FLAGS_CLEAR_ACA) { 759c5fd36edSAlexander Motin isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA", nphdl, notify.nt_lun, inp->in_seqid); 7602df76c16SMatt Jacob notify.nt_ncode = NT_CLEAR_ACA; 761ea49c6e4SMatt Jacob } else { 762c5fd36edSAlexander Motin isp_prt(isp, ISP_LOGWARN, f2, "task flag", inp->in_status, notify.nt_lun, nphdl, inp->in_task_flags, inp->in_seqid); 763387d8239SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inp); 764e5265237SMatt Jacob return; 765ea49c6e4SMatt Jacob } 7662df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 767ea49c6e4SMatt Jacob } 768ea49c6e4SMatt Jacob 76910365e5aSMatt Jacob static void 77010365e5aSMatt Jacob isp_got_tmf_24xx(ispsoftc_t *isp, at7_entry_t *aep) 77110365e5aSMatt Jacob { 7722df76c16SMatt Jacob isp_notify_t notify; 773c5fd36edSAlexander Motin static const char f1[] = "%s from PortID 0x%06x lun %x seq 0x%08x"; 774c5fd36edSAlexander Motin static const char f2[] = "unknown Task Flag 0x%x lun %x PortID 0x%x tag 0x%08x"; 775352427b3SAlexander Motin fcportdb_t *lp; 7762df76c16SMatt Jacob uint16_t chan; 7772df76c16SMatt Jacob uint32_t sid, did; 77810365e5aSMatt Jacob 7792df76c16SMatt Jacob ISP_MEMZERO(¬ify, sizeof (isp_notify_t)); 7802df76c16SMatt Jacob notify.nt_hba = isp; 7812df76c16SMatt Jacob notify.nt_wwn = INI_ANY; 7822df76c16SMatt Jacob notify.nt_lun = (aep->at_cmnd.fcp_cmnd_lun[0] << 8) | (aep->at_cmnd.fcp_cmnd_lun[1]); 7832df76c16SMatt Jacob notify.nt_tagval = aep->at_rxid; 7842df76c16SMatt Jacob notify.nt_tagval |= (((uint64_t)(isp->isp_serno++)) << 32); 7852df76c16SMatt Jacob notify.nt_lreserved = aep; 786352427b3SAlexander Motin sid = (aep->at_hdr.s_id[0] << 16) | (aep->at_hdr.s_id[1] << 8) | aep->at_hdr.s_id[2]; 7872df76c16SMatt Jacob did = (aep->at_hdr.d_id[0] << 16) | (aep->at_hdr.d_id[1] << 8) | aep->at_hdr.d_id[2]; 78893d07b9aSAlexander Motin if (ISP_CAP_MULTI_ID(isp) && isp->isp_nchan > 1) { 78993d07b9aSAlexander Motin /* Channel has to be derived from D_ID */ 79093d07b9aSAlexander Motin isp_find_chan_by_did(isp, did, &chan); 79193d07b9aSAlexander Motin if (chan == ISP_NOCHAN) { 7922df76c16SMatt Jacob isp_prt(isp, ISP_LOGWARN, "%s: D_ID 0x%x not found on any channel", __func__, did); 793352427b3SAlexander Motin isp_endcmd(isp, aep, NIL_HANDLE, ISP_NOCHAN, ECMD_TERMINATE, 0); 79410365e5aSMatt Jacob return; 79510365e5aSMatt Jacob } 79693d07b9aSAlexander Motin } else { 79793d07b9aSAlexander Motin chan = 0; 79893d07b9aSAlexander Motin } 799352427b3SAlexander Motin if (isp_find_pdb_by_portid(isp, chan, sid, &lp)) 800352427b3SAlexander Motin notify.nt_nphdl = lp->handle; 801352427b3SAlexander Motin else 802352427b3SAlexander Motin notify.nt_nphdl = NIL_HANDLE; 8032df76c16SMatt Jacob notify.nt_sid = sid; 8042df76c16SMatt Jacob notify.nt_did = did; 8052df76c16SMatt Jacob notify.nt_channel = chan; 806c98d2b1fSAlexander Motin if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_QUERY_TASK_SET) { 807c98d2b1fSAlexander Motin isp_prt(isp, ISP_LOGINFO, f1, "QUERY TASK SET", sid, notify.nt_lun, aep->at_rxid); 808c98d2b1fSAlexander Motin notify.nt_ncode = NT_QUERY_TASK_SET; 809c98d2b1fSAlexander Motin } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_ABORT_TASK_SET) { 8102df76c16SMatt Jacob isp_prt(isp, ISP_LOGINFO, f1, "ABORT TASK SET", sid, notify.nt_lun, aep->at_rxid); 8112df76c16SMatt Jacob notify.nt_ncode = NT_ABORT_TASK_SET; 8122df76c16SMatt Jacob } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_CLEAR_TASK_SET) { 8132df76c16SMatt Jacob isp_prt(isp, ISP_LOGINFO, f1, "CLEAR TASK SET", sid, notify.nt_lun, aep->at_rxid); 8142df76c16SMatt Jacob notify.nt_ncode = NT_CLEAR_TASK_SET; 815c98d2b1fSAlexander Motin } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_QUERY_ASYNC_EVENT) { 816c98d2b1fSAlexander Motin isp_prt(isp, ISP_LOGINFO, f1, "QUERY ASYNC EVENT", sid, notify.nt_lun, aep->at_rxid); 817c98d2b1fSAlexander Motin notify.nt_ncode = NT_QUERY_ASYNC_EVENT; 8182df76c16SMatt Jacob } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_LUN_RESET) { 8192df76c16SMatt Jacob isp_prt(isp, ISP_LOGINFO, f1, "LUN RESET", sid, notify.nt_lun, aep->at_rxid); 8202df76c16SMatt Jacob notify.nt_ncode = NT_LUN_RESET; 8212df76c16SMatt Jacob } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_TGT_RESET) { 8222df76c16SMatt Jacob isp_prt(isp, ISP_LOGINFO, f1, "TARGET RESET", sid, notify.nt_lun, aep->at_rxid); 8232df76c16SMatt Jacob notify.nt_ncode = NT_TARGET_RESET; 8242df76c16SMatt Jacob } else if (aep->at_cmnd.fcp_cmnd_task_management & FCP_CMND_TMF_CLEAR_ACA) { 8252df76c16SMatt Jacob isp_prt(isp, ISP_LOGINFO, f1, "CLEAR ACA", sid, notify.nt_lun, aep->at_rxid); 8262df76c16SMatt Jacob notify.nt_ncode = NT_CLEAR_ACA; 8272df76c16SMatt Jacob } else { 8282df76c16SMatt Jacob isp_prt(isp, ISP_LOGWARN, f2, aep->at_cmnd.fcp_cmnd_task_management, notify.nt_lun, sid, aep->at_rxid); 8292df76c16SMatt Jacob notify.nt_ncode = NT_UNKNOWN; 830352427b3SAlexander Motin isp_endcmd(isp, aep, notify.nt_nphdl, chan, ECMD_RVALID | (0x4 << 12), 0); 8312df76c16SMatt Jacob return; 8322df76c16SMatt Jacob } 8332df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY, ¬ify); 83410365e5aSMatt Jacob } 83510365e5aSMatt Jacob 8362df76c16SMatt Jacob int 8379cd7268eSMatt Jacob isp_notify_ack(ispsoftc_t *isp, void *arg) 838ea49c6e4SMatt Jacob { 839ea49c6e4SMatt Jacob char storage[QENTRY_LEN]; 840ea49c6e4SMatt Jacob void *outp; 841ea49c6e4SMatt Jacob 8422df76c16SMatt Jacob /* 8432df76c16SMatt Jacob * This is in case a Task Management Function ends up here. 8442df76c16SMatt Jacob */ 84510365e5aSMatt Jacob if (IS_24XX(isp) && arg != NULL && (((isphdr_t *)arg)->rqs_entry_type == RQSTYPE_ATIO)) { 84610365e5aSMatt Jacob at7_entry_t *aep = arg; 8472df76c16SMatt Jacob return (isp_endcmd(isp, aep, NIL_HANDLE, 0, 0, 0)); 8482df76c16SMatt Jacob } 8492df76c16SMatt Jacob 8502df76c16SMatt Jacob outp = isp_getrqentry(isp); 8512df76c16SMatt Jacob if (outp == NULL) { 8522df76c16SMatt Jacob isp_prt(isp, ISP_LOGWARN, rqo, __func__); 8532df76c16SMatt Jacob return (1); 8542df76c16SMatt Jacob } 8552df76c16SMatt Jacob 8562df76c16SMatt Jacob ISP_MEMZERO(storage, QENTRY_LEN); 8572df76c16SMatt Jacob 8582df76c16SMatt Jacob if (IS_24XX(isp)) { 85910365e5aSMatt Jacob na_fcentry_24xx_t *na = (na_fcentry_24xx_t *) storage; 860387d8239SMatt Jacob na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; 861387d8239SMatt Jacob na->na_header.rqs_entry_count = 1; 86210365e5aSMatt Jacob if (arg) { 86310365e5aSMatt Jacob in_fcentry_24xx_t *in = arg; 86410365e5aSMatt Jacob na->na_nphdl = in->in_nphdl; 865387d8239SMatt Jacob na->na_flags = in->in_flags; 86610365e5aSMatt Jacob na->na_status = in->in_status; 86710365e5aSMatt Jacob na->na_status_subcode = in->in_status_subcode; 86837a7daacSAlexander Motin na->na_fwhandle = in->in_fwhandle; 86910365e5aSMatt Jacob na->na_rxid = in->in_rxid; 87010365e5aSMatt Jacob na->na_oxid = in->in_oxid; 8712df76c16SMatt Jacob na->na_vpidx = in->in_vpidx; 87210365e5aSMatt Jacob if (in->in_status == IN24XX_SRR_RCVD) { 87310365e5aSMatt Jacob na->na_srr_rxid = in->in_srr_rxid; 87410365e5aSMatt Jacob na->na_srr_reloff_hi = in->in_srr_reloff_hi; 87510365e5aSMatt Jacob na->na_srr_reloff_lo = in->in_srr_reloff_lo; 87610365e5aSMatt Jacob na->na_srr_iu = in->in_srr_iu; 877387d8239SMatt Jacob /* 878387d8239SMatt Jacob * Whether we're accepting the SRR or rejecting 879387d8239SMatt Jacob * it is determined by looking at the in_reserved 880387d8239SMatt Jacob * field in the original notify structure. 881387d8239SMatt Jacob */ 882387d8239SMatt Jacob if (in->in_reserved) { 88310365e5aSMatt Jacob na->na_srr_flags = 1; 88410365e5aSMatt Jacob na->na_srr_reject_vunique = 0; 885387d8239SMatt Jacob na->na_srr_reject_code = 9; /* unable to perform this command at this time */ 886387d8239SMatt Jacob na->na_srr_reject_explanation = 0x2a; /* unable to supply the requested data */ 88710365e5aSMatt Jacob } 88810365e5aSMatt Jacob } 889387d8239SMatt Jacob } 89010365e5aSMatt Jacob isp_put_notify_24xx_ack(isp, na, (na_fcentry_24xx_t *)outp); 8913e6deb33SAlexander Motin } else { 892ea49c6e4SMatt Jacob na_fcentry_t *na = (na_fcentry_t *) storage; 893b4110d46SMatt Jacob int iid = 0; 894b4110d46SMatt Jacob 895ea49c6e4SMatt Jacob if (arg) { 896ea49c6e4SMatt Jacob in_fcentry_t *inp = arg; 8972df76c16SMatt Jacob ISP_MEMCPY(storage, arg, sizeof (isphdr_t)); 8982df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 8992df76c16SMatt Jacob ((na_fcentry_e_t *)na)->na_iid = ((in_fcentry_e_t *)inp)->in_iid; 900b4110d46SMatt Jacob iid = ((na_fcentry_e_t *)na)->na_iid; 901e5265237SMatt Jacob } else { 902ea49c6e4SMatt Jacob na->na_iid = inp->in_iid; 903b4110d46SMatt Jacob iid = na->na_iid; 904e5265237SMatt Jacob } 9052df76c16SMatt Jacob na->na_task_flags = inp->in_task_flags & TASK_FLAGS_RESERVED_MASK; 906ea49c6e4SMatt Jacob na->na_seqid = inp->in_seqid; 90775c1e828SMatt Jacob na->na_status = inp->in_status; 908387d8239SMatt Jacob na->na_flags = NAFC_RCOUNT; 909ea49c6e4SMatt Jacob if (inp->in_status == IN_RESET) { 910387d8239SMatt Jacob na->na_flags = NAFC_RST_CLRD; /* We do not modify resource counts for LIP resets */ 911ea49c6e4SMatt Jacob } 912b4110d46SMatt Jacob if (inp->in_status == IN_MSG_RECEIVED) { 913b4110d46SMatt Jacob na->na_flags |= NAFC_TVALID; 914b4110d46SMatt Jacob na->na_response = 0; /* XXX SUCCEEDED XXX */ 915b4110d46SMatt Jacob } 916ea49c6e4SMatt Jacob } else { 917ea49c6e4SMatt Jacob na->na_flags = NAFC_RST_CLRD; 918ea49c6e4SMatt Jacob } 9199dae8807SMatt Jacob na->na_header.rqs_entry_type = RQSTYPE_NOTIFY_ACK; 9209dae8807SMatt Jacob na->na_header.rqs_entry_count = 1; 9212df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 9222df76c16SMatt Jacob isp_put_notify_ack_fc_e(isp, (na_fcentry_e_t *) na, (na_fcentry_e_t *)outp); 923e5265237SMatt Jacob } else { 9244fd13c1bSMatt Jacob isp_put_notify_ack_fc(isp, na, (na_fcentry_t *)outp); 925e5265237SMatt Jacob } 926c5fd36edSAlexander Motin isp_prt(isp, ISP_LOGTDEBUG0, "notify ack handle %x seqid %x flags %x tflags %x response %x", iid, na->na_seqid, 927b4110d46SMatt Jacob na->na_flags, na->na_task_flags, na->na_response); 928ea49c6e4SMatt Jacob } 9292df76c16SMatt Jacob ISP_TDQE(isp, "isp_notify_ack", isp->isp_reqidx, storage); 9302df76c16SMatt Jacob ISP_SYNC_REQUEST(isp); 9312df76c16SMatt Jacob return (0); 9322df76c16SMatt Jacob } 9332df76c16SMatt Jacob 9342df76c16SMatt Jacob int 9352df76c16SMatt Jacob isp_acknak_abts(ispsoftc_t *isp, void *arg, int errno) 9362df76c16SMatt Jacob { 9372df76c16SMatt Jacob char storage[QENTRY_LEN]; 9382df76c16SMatt Jacob uint16_t tmpw; 9392df76c16SMatt Jacob uint8_t tmpb; 9402df76c16SMatt Jacob abts_t *abts = arg; 9412df76c16SMatt Jacob abts_rsp_t *rsp = (abts_rsp_t *) storage; 9422df76c16SMatt Jacob void *outp; 9432df76c16SMatt Jacob 9442df76c16SMatt Jacob if (!IS_24XX(isp)) { 9452df76c16SMatt Jacob isp_prt(isp, ISP_LOGERR, "%s: called for non-24XX card", __func__); 9462df76c16SMatt Jacob return (0); 9472df76c16SMatt Jacob } 9482df76c16SMatt Jacob 9492df76c16SMatt Jacob if (abts->abts_header.rqs_entry_type != RQSTYPE_ABTS_RCVD) { 9502df76c16SMatt Jacob isp_prt(isp, ISP_LOGERR, "%s: called for non-ABTS entry (0x%x)", __func__, abts->abts_header.rqs_entry_type); 9512df76c16SMatt Jacob return (0); 9522df76c16SMatt Jacob } 9532df76c16SMatt Jacob 9542df76c16SMatt Jacob outp = isp_getrqentry(isp); 9552df76c16SMatt Jacob if (outp == NULL) { 9562df76c16SMatt Jacob isp_prt(isp, ISP_LOGWARN, rqo, __func__); 9572df76c16SMatt Jacob return (1); 9582df76c16SMatt Jacob } 9592df76c16SMatt Jacob 9602df76c16SMatt Jacob ISP_MEMCPY(rsp, abts, QENTRY_LEN); 9612df76c16SMatt Jacob rsp->abts_rsp_header.rqs_entry_type = RQSTYPE_ABTS_RSP; 9622df76c16SMatt Jacob 9632df76c16SMatt Jacob /* 9642df76c16SMatt Jacob * Swap destination and source for response. 9652df76c16SMatt Jacob */ 9662df76c16SMatt Jacob rsp->abts_rsp_r_ctl = BA_ACC; 9672df76c16SMatt Jacob tmpw = rsp->abts_rsp_did_lo; 9682df76c16SMatt Jacob tmpb = rsp->abts_rsp_did_hi; 9692df76c16SMatt Jacob rsp->abts_rsp_did_lo = rsp->abts_rsp_sid_lo; 9702df76c16SMatt Jacob rsp->abts_rsp_did_hi = rsp->abts_rsp_sid_hi; 9712df76c16SMatt Jacob rsp->abts_rsp_sid_lo = tmpw; 9722df76c16SMatt Jacob rsp->abts_rsp_sid_hi = tmpb; 9732df76c16SMatt Jacob 9742df76c16SMatt Jacob rsp->abts_rsp_f_ctl_hi ^= 0x80; /* invert Exchange Context */ 9752df76c16SMatt Jacob rsp->abts_rsp_f_ctl_hi &= ~0x7f; /* clear Sequence Initiator and other bits */ 9762df76c16SMatt Jacob rsp->abts_rsp_f_ctl_hi |= 0x10; /* abort the whole exchange */ 9772df76c16SMatt Jacob rsp->abts_rsp_f_ctl_hi |= 0x8; /* last data frame of sequence */ 9782df76c16SMatt Jacob rsp->abts_rsp_f_ctl_hi |= 0x1; /* transfer Sequence Initiative */ 9792df76c16SMatt Jacob rsp->abts_rsp_f_ctl_lo = 0; 9802df76c16SMatt Jacob 9812df76c16SMatt Jacob if (errno == 0) { 9822df76c16SMatt Jacob uint16_t rx_id, ox_id; 9832df76c16SMatt Jacob 9842df76c16SMatt Jacob rx_id = rsp->abts_rsp_rx_id; 9852df76c16SMatt Jacob ox_id = rsp->abts_rsp_ox_id; 9862df76c16SMatt Jacob ISP_MEMZERO(&rsp->abts_rsp_payload.ba_acc, sizeof (rsp->abts_rsp_payload.ba_acc)); 9872df76c16SMatt Jacob isp_prt(isp, ISP_LOGTINFO, "[0x%x] ABTS of 0x%x being BA_ACC'd", rsp->abts_rsp_rxid_abts, rsp->abts_rsp_rxid_task); 9882df76c16SMatt Jacob rsp->abts_rsp_payload.ba_acc.aborted_rx_id = rx_id; 9892df76c16SMatt Jacob rsp->abts_rsp_payload.ba_acc.aborted_ox_id = ox_id; 9902df76c16SMatt Jacob rsp->abts_rsp_payload.ba_acc.high_seq_cnt = 0xffff; 9912df76c16SMatt Jacob } else { 9922df76c16SMatt Jacob ISP_MEMZERO(&rsp->abts_rsp_payload.ba_rjt, sizeof (rsp->abts_rsp_payload.ba_acc)); 9932df76c16SMatt Jacob switch (errno) { 9942df76c16SMatt Jacob case ENOMEM: 995387d8239SMatt Jacob rsp->abts_rsp_payload.ba_rjt.reason = 5; /* Logical Unit Busy */ 9962df76c16SMatt Jacob break; 9972df76c16SMatt Jacob default: 9982df76c16SMatt Jacob rsp->abts_rsp_payload.ba_rjt.reason = 9; /* Unable to perform command request */ 9992df76c16SMatt Jacob break; 10002df76c16SMatt Jacob } 10012df76c16SMatt Jacob } 10022df76c16SMatt Jacob 10032df76c16SMatt Jacob /* 10042df76c16SMatt Jacob * The caller will have set response values as appropriate 10052df76c16SMatt Jacob * in the ABTS structure just before calling us. 10062df76c16SMatt Jacob */ 10072df76c16SMatt Jacob isp_put_abts_rsp(isp, rsp, (abts_rsp_t *)outp); 10082df76c16SMatt Jacob ISP_TDQE(isp, "isp_acknak_abts", isp->isp_reqidx, storage); 10092df76c16SMatt Jacob ISP_SYNC_REQUEST(isp); 10102df76c16SMatt Jacob return (0); 1011ea49c6e4SMatt Jacob } 1012ea49c6e4SMatt Jacob 1013ea49c6e4SMatt Jacob static void 10149cd7268eSMatt Jacob isp_handle_atio2(ispsoftc_t *isp, at2_entry_t *aep) 1015ea49c6e4SMatt Jacob { 1016e5265237SMatt Jacob int lun, iid; 10172133e16fSMatt Jacob 10182df76c16SMatt Jacob if (ISP_CAP_SCCFW(isp)) { 1019ea49c6e4SMatt Jacob lun = aep->at_scclun; 10206af11b82SAlexander Motin #if __FreeBSD_version < 1000700 10216af11b82SAlexander Motin lun &= 0x3fff; 10226af11b82SAlexander Motin #endif 10232133e16fSMatt Jacob } else { 1024ea49c6e4SMatt Jacob lun = aep->at_lun; 10252133e16fSMatt Jacob } 10262133e16fSMatt Jacob 10272df76c16SMatt Jacob if (ISP_CAP_2KLOGIN(isp)) { 1028e5265237SMatt Jacob iid = ((at2e_entry_t *)aep)->at_iid; 1029e5265237SMatt Jacob } else { 1030e5265237SMatt Jacob iid = aep->at_iid; 1031e5265237SMatt Jacob } 1032e5265237SMatt Jacob 1033ea49c6e4SMatt Jacob /* 1034ea49c6e4SMatt Jacob * The firmware status (except for the QLTM_SVALID bit) indicates 1035ea49c6e4SMatt Jacob * why this ATIO was sent to us. 1036ea49c6e4SMatt Jacob * 1037ea49c6e4SMatt Jacob * If QLTM_SVALID is set, the firware has recommended Sense Data. 1038ea49c6e4SMatt Jacob * 1039ea49c6e4SMatt Jacob * If the DISCONNECTS DISABLED bit is set in the flags field, 1040ea49c6e4SMatt Jacob * we're still connected on the SCSI bus - i.e. the initiator 1041ea49c6e4SMatt Jacob * did not set DiscPriv in the identify message. We don't care 1042ea49c6e4SMatt Jacob * about this so it's ignored. 1043ea49c6e4SMatt Jacob */ 1044ea49c6e4SMatt Jacob 1045ea49c6e4SMatt Jacob switch (aep->at_status & ~QLTM_SVALID) { 1046ea49c6e4SMatt Jacob case AT_PATH_INVALID: 1047ea49c6e4SMatt Jacob /* 1048ea49c6e4SMatt Jacob * ATIO rejected by the firmware due to disabled lun. 1049ea49c6e4SMatt Jacob */ 10506af11b82SAlexander Motin isp_prt(isp, ISP_LOGERR, "rejected ATIO2 for disabled lun %x", lun); 1051ea49c6e4SMatt Jacob break; 1052ea49c6e4SMatt Jacob case AT_NOCAP: 1053ea49c6e4SMatt Jacob /* 1054ea49c6e4SMatt Jacob * Requested Capability not available 1055ea49c6e4SMatt Jacob * We sent an ATIO that overflowed the firmware's 1056ea49c6e4SMatt Jacob * command resource count. 1057ea49c6e4SMatt Jacob */ 10586af11b82SAlexander Motin isp_prt(isp, ISP_LOGERR, "rejected ATIO2 for lun %x- command count overflow", lun); 1059ea49c6e4SMatt Jacob break; 1060ea49c6e4SMatt Jacob 1061ea49c6e4SMatt Jacob case AT_BDR_MSG: 1062ea49c6e4SMatt Jacob /* 1063ea49c6e4SMatt Jacob * If we send an ATIO to the firmware to increment 1064ea49c6e4SMatt Jacob * its command resource count, and the firmware is 1065ea49c6e4SMatt Jacob * recovering from a Bus Device Reset, it returns 1066ea49c6e4SMatt Jacob * the ATIO with this status. We set the command 1067ea49c6e4SMatt Jacob * resource count in the Enable Lun entry and no 1068ea49c6e4SMatt Jacob * not increment it. Therefore we should never get 1069ea49c6e4SMatt Jacob * this status here. 1070ea49c6e4SMatt Jacob */ 107123ac1fceSMatt Jacob isp_prt(isp, ISP_LOGERR, atiocope, lun, 0); 1072ea49c6e4SMatt Jacob break; 1073ea49c6e4SMatt Jacob 1074ea49c6e4SMatt Jacob case AT_CDB: /* Got a CDB */ 1075ea49c6e4SMatt Jacob /* 1076ea49c6e4SMatt Jacob * Punt to platform specific layer. 1077ea49c6e4SMatt Jacob */ 10782df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_ACTION, aep); 1079ea49c6e4SMatt Jacob break; 1080ea49c6e4SMatt Jacob 1081ea49c6e4SMatt Jacob case AT_RESET: 1082ea49c6e4SMatt Jacob /* 1083ea49c6e4SMatt Jacob * A bus reset came along an blew away this command. Why 1084ea49c6e4SMatt Jacob * they do this in addition the async event code stuff, 1085ea49c6e4SMatt Jacob * I dunno. 1086ea49c6e4SMatt Jacob * 1087ea49c6e4SMatt Jacob * Ignore it because the async event will clear things 1088ea49c6e4SMatt Jacob * up for us. 1089ea49c6e4SMatt Jacob */ 1090e5265237SMatt Jacob isp_prt(isp, ISP_LOGERR, atior, lun, iid, 0); 1091ea49c6e4SMatt Jacob break; 1092ea49c6e4SMatt Jacob 1093ea49c6e4SMatt Jacob 1094ea49c6e4SMatt Jacob default: 1095c5fd36edSAlexander Motin isp_prt(isp, ISP_LOGERR, "Unknown ATIO2 status 0x%x from handle %d for lun %x", aep->at_status, iid, lun); 1096b25bcef8SMatt Jacob (void) isp_target_put_atio(isp, aep); 1097ea49c6e4SMatt Jacob break; 1098ea49c6e4SMatt Jacob } 1099ea49c6e4SMatt Jacob } 1100ea49c6e4SMatt Jacob 1101ea49c6e4SMatt Jacob static void 11029cd7268eSMatt Jacob isp_handle_ctio2(ispsoftc_t *isp, ct2_entry_t *ct) 1103ea49c6e4SMatt Jacob { 110410365e5aSMatt Jacob void *xs; 110510549c05SMatt Jacob int pl = ISP_LOGTDEBUG2; 1106ea49c6e4SMatt Jacob char *fmsg = NULL; 1107ea49c6e4SMatt Jacob 1108b0bd9b71SMatt Jacob if (ct->ct_syshandle) { 1109970ceb2fSAlexander Motin xs = isp_find_xs(isp, ct->ct_syshandle); 111010365e5aSMatt Jacob if (xs == NULL) { 111110549c05SMatt Jacob pl = ISP_LOGALL; 111210365e5aSMatt Jacob } 1113ea49c6e4SMatt Jacob } else { 1114ea49c6e4SMatt Jacob xs = NULL; 1115ea49c6e4SMatt Jacob } 1116ea49c6e4SMatt Jacob 1117ea49c6e4SMatt Jacob switch (ct->ct_status & ~QLTM_SVALID) { 11185d571944SMatt Jacob case CT_BUS_ERROR: 11195d571944SMatt Jacob isp_prt(isp, ISP_LOGERR, "PCI DMA Bus Error"); 11205d571944SMatt Jacob /* FALL Through */ 11215d571944SMatt Jacob case CT_DATA_OVER: 11225d571944SMatt Jacob case CT_DATA_UNDER: 1123ea49c6e4SMatt Jacob case CT_OK: 1124ea49c6e4SMatt Jacob /* 1125ea49c6e4SMatt Jacob * There are generally 2 possibilities as to why we'd get 1126ea49c6e4SMatt Jacob * this condition: 1127ea49c6e4SMatt Jacob * We sent or received data. 1128ea49c6e4SMatt Jacob * We sent status & command complete. 1129ea49c6e4SMatt Jacob */ 1130ea49c6e4SMatt Jacob 1131ea49c6e4SMatt Jacob break; 1132ea49c6e4SMatt Jacob 1133ea49c6e4SMatt Jacob case CT_BDR_MSG: 1134ea49c6e4SMatt Jacob /* 11355d571944SMatt Jacob * Target Reset function received. 1136ea49c6e4SMatt Jacob * 1137976b0106SKevin Lo * The firmware generates an async mailbox interrupt to 1138ea49c6e4SMatt Jacob * notify us of this and returns outstanding CTIOs with this 1139ea49c6e4SMatt Jacob * status. These CTIOs are handled in that same way as 1140ea49c6e4SMatt Jacob * CT_ABORTED ones, so just fall through here. 1141ea49c6e4SMatt Jacob */ 114210365e5aSMatt Jacob fmsg = "TARGET RESET"; 1143ea49c6e4SMatt Jacob /*FALLTHROUGH*/ 1144ea49c6e4SMatt Jacob case CT_RESET: 1145ea49c6e4SMatt Jacob if (fmsg == NULL) 11465d571944SMatt Jacob fmsg = "LIP Reset"; 1147ea49c6e4SMatt Jacob /*FALLTHROUGH*/ 1148ea49c6e4SMatt Jacob case CT_ABORTED: 1149ea49c6e4SMatt Jacob /* 1150ea49c6e4SMatt Jacob * When an Abort message is received the firmware goes to 1151ea49c6e4SMatt Jacob * Bus Free and returns all outstanding CTIOs with the status 1152ea49c6e4SMatt Jacob * set, then sends us an Immediate Notify entry. 1153ea49c6e4SMatt Jacob */ 115410365e5aSMatt Jacob if (fmsg == NULL) { 115510365e5aSMatt Jacob fmsg = "ABORT"; 115610365e5aSMatt Jacob } 1157ea49c6e4SMatt Jacob 11582df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "CTIO2 destroyed by %s: RX_ID=0x%x", fmsg, ct->ct_rxid); 1159ea49c6e4SMatt Jacob break; 1160ea49c6e4SMatt Jacob 1161ea49c6e4SMatt Jacob case CT_INVAL: 1162ea49c6e4SMatt Jacob /* 11630c02c31bSMatt Jacob * CTIO rejected by the firmware - invalid data direction. 1164ea49c6e4SMatt Jacob */ 11652f9e7606SMatt Jacob isp_prt(isp, ISP_LOGERR, "CTIO2 had wrong data direction"); 1166ea49c6e4SMatt Jacob break; 1167ea49c6e4SMatt Jacob 1168ea49c6e4SMatt Jacob case CT_RSELTMO: 11695d571944SMatt Jacob fmsg = "failure to reconnect to initiator"; 1170ea49c6e4SMatt Jacob /*FALLTHROUGH*/ 1171ea49c6e4SMatt Jacob case CT_TIMEOUT: 1172ea49c6e4SMatt Jacob if (fmsg == NULL) 11735d571944SMatt Jacob fmsg = "command"; 11742df76c16SMatt Jacob isp_prt(isp, ISP_LOGWARN, "Firmware timed out on %s", fmsg); 1175ea49c6e4SMatt Jacob break; 1176ea49c6e4SMatt Jacob 1177ea49c6e4SMatt Jacob case CT_ERR: 1178ea49c6e4SMatt Jacob fmsg = "Completed with Error"; 1179ea49c6e4SMatt Jacob /*FALLTHROUGH*/ 1180ea49c6e4SMatt Jacob case CT_LOGOUT: 1181ea49c6e4SMatt Jacob if (fmsg == NULL) 1182ea49c6e4SMatt Jacob fmsg = "Port Logout"; 1183ea49c6e4SMatt Jacob /*FALLTHROUGH*/ 118410365e5aSMatt Jacob case CT_PORTUNAVAIL: 1185ea49c6e4SMatt Jacob if (fmsg == NULL) 1186ea49c6e4SMatt Jacob fmsg = "Port not available"; 1187a0fb4cf1SPoul-Henning Kamp /*FALLTHROUGH*/ 11885d571944SMatt Jacob case CT_PORTCHANGED: 11895d571944SMatt Jacob if (fmsg == NULL) 11905d571944SMatt Jacob fmsg = "Port Changed"; 1191a0fb4cf1SPoul-Henning Kamp /*FALLTHROUGH*/ 1192ea49c6e4SMatt Jacob case CT_NOACK: 1193ea49c6e4SMatt Jacob if (fmsg == NULL) 1194ea49c6e4SMatt Jacob fmsg = "unacknowledged Immediate Notify pending"; 119510365e5aSMatt Jacob isp_prt(isp, ISP_LOGWARN, "CTIO returned by f/w- %s", fmsg); 1196ea49c6e4SMatt Jacob break; 1197ea49c6e4SMatt Jacob 1198ea49c6e4SMatt Jacob case CT_INVRXID: 1199ea49c6e4SMatt Jacob /* 1200ea49c6e4SMatt Jacob * CTIO rejected by the firmware because an invalid RX_ID. 1201ea49c6e4SMatt Jacob * Just print a message. 1202ea49c6e4SMatt Jacob */ 12032df76c16SMatt Jacob isp_prt(isp, ISP_LOGWARN, "CTIO2 completed with Invalid RX_ID 0x%x", ct->ct_rxid); 1204ea49c6e4SMatt Jacob break; 1205ea49c6e4SMatt Jacob 1206ea49c6e4SMatt Jacob default: 12072df76c16SMatt Jacob isp_prt(isp, ISP_LOGERR, "Unknown CTIO2 status 0x%x", ct->ct_status & ~QLTM_SVALID); 1208ea49c6e4SMatt Jacob break; 1209ea49c6e4SMatt Jacob } 1210ea49c6e4SMatt Jacob 1211ea49c6e4SMatt Jacob if (xs == NULL) { 1212ea49c6e4SMatt Jacob /* 1213ea49c6e4SMatt Jacob * There may be more than one CTIO for a data transfer, 1214ea49c6e4SMatt Jacob * or this may be a status CTIO we're not monitoring. 1215ea49c6e4SMatt Jacob * 1216ea49c6e4SMatt Jacob * The assumption is that they'll all be returned in the 1217ea49c6e4SMatt Jacob * order we got them. 1218ea49c6e4SMatt Jacob */ 1219b0bd9b71SMatt Jacob if (ct->ct_syshandle == 0) { 1220ac9d0a02SMatt Jacob if ((ct->ct_flags & CT2_SENDSTATUS) == 0) { 12212df76c16SMatt Jacob isp_prt(isp, pl, "intermediate CTIO completed ok"); 1222ea49c6e4SMatt Jacob } else { 12232df76c16SMatt Jacob isp_prt(isp, pl, "unmonitored CTIO completed ok"); 1224ea49c6e4SMatt Jacob } 1225ea49c6e4SMatt Jacob } else { 12262df76c16SMatt Jacob isp_prt(isp, pl, "NO xs for CTIO (handle 0x%x) status 0x%x", ct->ct_syshandle, ct->ct_status & ~QLTM_SVALID); 1227ea49c6e4SMatt Jacob } 1228ea49c6e4SMatt Jacob } else { 12295d571944SMatt Jacob if ((ct->ct_flags & CT2_DATAMASK) != CT2_NO_DATA) { 12305d571944SMatt Jacob ISP_DMAFREE(isp, xs, ct->ct_syshandle); 12315d571944SMatt Jacob } 1232ac9d0a02SMatt Jacob if (ct->ct_flags & CT2_SENDSTATUS) { 1233ea49c6e4SMatt Jacob /* 1234ea49c6e4SMatt Jacob * Sent status and command complete. 1235ea49c6e4SMatt Jacob * 1236ea49c6e4SMatt Jacob * We're now really done with this command, so we 1237ea49c6e4SMatt Jacob * punt to the platform dependent layers because 1238ea49c6e4SMatt Jacob * only there can we do the appropriate command 1239ea49c6e4SMatt Jacob * complete thread synchronization. 1240ea49c6e4SMatt Jacob */ 124110549c05SMatt Jacob isp_prt(isp, pl, "status CTIO complete"); 1242ea49c6e4SMatt Jacob } else { 1243ea49c6e4SMatt Jacob /* 1244ea49c6e4SMatt Jacob * Final CTIO completed. Release DMA resources and 1245ea49c6e4SMatt Jacob * notify platform dependent layers. 1246ea49c6e4SMatt Jacob */ 124710549c05SMatt Jacob isp_prt(isp, pl, "data CTIO complete"); 1248ea49c6e4SMatt Jacob } 12492df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_ACTION, ct); 1250ea49c6e4SMatt Jacob /* 1251ea49c6e4SMatt Jacob * The platform layer will destroy the handle if appropriate. 1252ea49c6e4SMatt Jacob */ 1253ea49c6e4SMatt Jacob } 1254ea49c6e4SMatt Jacob } 125510365e5aSMatt Jacob 125610365e5aSMatt Jacob static void 125710365e5aSMatt Jacob isp_handle_ctio7(ispsoftc_t *isp, ct7_entry_t *ct) 125810365e5aSMatt Jacob { 125910365e5aSMatt Jacob void *xs; 126010365e5aSMatt Jacob int pl = ISP_LOGTDEBUG2; 126110365e5aSMatt Jacob char *fmsg = NULL; 126210365e5aSMatt Jacob 126310365e5aSMatt Jacob if (ct->ct_syshandle) { 1264970ceb2fSAlexander Motin xs = isp_find_xs(isp, ct->ct_syshandle); 126510365e5aSMatt Jacob if (xs == NULL) { 126610365e5aSMatt Jacob pl = ISP_LOGALL; 126710365e5aSMatt Jacob } 126810365e5aSMatt Jacob } else { 126910365e5aSMatt Jacob xs = NULL; 127010365e5aSMatt Jacob } 127110365e5aSMatt Jacob 127210365e5aSMatt Jacob switch (ct->ct_nphdl) { 127310365e5aSMatt Jacob case CT7_BUS_ERROR: 127410365e5aSMatt Jacob isp_prt(isp, ISP_LOGERR, "PCI DMA Bus Error"); 127510365e5aSMatt Jacob /* FALL Through */ 127610365e5aSMatt Jacob case CT7_DATA_OVER: 127710365e5aSMatt Jacob case CT7_DATA_UNDER: 127810365e5aSMatt Jacob case CT7_OK: 127910365e5aSMatt Jacob /* 128010365e5aSMatt Jacob * There are generally 2 possibilities as to why we'd get 128110365e5aSMatt Jacob * this condition: 128210365e5aSMatt Jacob * We sent or received data. 128310365e5aSMatt Jacob * We sent status & command complete. 128410365e5aSMatt Jacob */ 128510365e5aSMatt Jacob 128610365e5aSMatt Jacob break; 128710365e5aSMatt Jacob 128810365e5aSMatt Jacob case CT7_RESET: 128910365e5aSMatt Jacob if (fmsg == NULL) { 129010365e5aSMatt Jacob fmsg = "LIP Reset"; 129110365e5aSMatt Jacob } 129210365e5aSMatt Jacob /*FALLTHROUGH*/ 129310365e5aSMatt Jacob case CT7_ABORTED: 129410365e5aSMatt Jacob /* 129510365e5aSMatt Jacob * When an Abort message is received the firmware goes to 129610365e5aSMatt Jacob * Bus Free and returns all outstanding CTIOs with the status 129710365e5aSMatt Jacob * set, then sends us an Immediate Notify entry. 129810365e5aSMatt Jacob */ 129910365e5aSMatt Jacob if (fmsg == NULL) { 130010365e5aSMatt Jacob fmsg = "ABORT"; 130110365e5aSMatt Jacob } 13022df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "CTIO7 destroyed by %s: RX_ID=0x%x", fmsg, ct->ct_rxid); 130310365e5aSMatt Jacob break; 130410365e5aSMatt Jacob 130510365e5aSMatt Jacob case CT7_TIMEOUT: 130610365e5aSMatt Jacob if (fmsg == NULL) { 130710365e5aSMatt Jacob fmsg = "command"; 130810365e5aSMatt Jacob } 13092df76c16SMatt Jacob isp_prt(isp, ISP_LOGWARN, "Firmware timed out on %s", fmsg); 131010365e5aSMatt Jacob break; 131110365e5aSMatt Jacob 131210365e5aSMatt Jacob case CT7_ERR: 131310365e5aSMatt Jacob fmsg = "Completed with Error"; 131410365e5aSMatt Jacob /*FALLTHROUGH*/ 131510365e5aSMatt Jacob case CT7_LOGOUT: 131610365e5aSMatt Jacob if (fmsg == NULL) { 131710365e5aSMatt Jacob fmsg = "Port Logout"; 131810365e5aSMatt Jacob } 131910365e5aSMatt Jacob /*FALLTHROUGH*/ 132010365e5aSMatt Jacob case CT7_PORTUNAVAIL: 132110365e5aSMatt Jacob if (fmsg == NULL) { 132210365e5aSMatt Jacob fmsg = "Port not available"; 132310365e5aSMatt Jacob } 132410365e5aSMatt Jacob /*FALLTHROUGH*/ 132510365e5aSMatt Jacob case CT7_PORTCHANGED: 132610365e5aSMatt Jacob if (fmsg == NULL) { 132710365e5aSMatt Jacob fmsg = "Port Changed"; 132810365e5aSMatt Jacob } 132910365e5aSMatt Jacob isp_prt(isp, ISP_LOGWARN, "CTIO returned by f/w- %s", fmsg); 133010365e5aSMatt Jacob break; 133110365e5aSMatt Jacob 133210365e5aSMatt Jacob case CT7_INVRXID: 133310365e5aSMatt Jacob /* 133410365e5aSMatt Jacob * CTIO rejected by the firmware because an invalid RX_ID. 133510365e5aSMatt Jacob * Just print a message. 133610365e5aSMatt Jacob */ 13372df76c16SMatt Jacob isp_prt(isp, ISP_LOGWARN, "CTIO7 completed with Invalid RX_ID 0x%x", ct->ct_rxid); 133810365e5aSMatt Jacob break; 133910365e5aSMatt Jacob 134010365e5aSMatt Jacob case CT7_REASSY_ERR: 134110365e5aSMatt Jacob isp_prt(isp, ISP_LOGWARN, "reassembly error"); 134210365e5aSMatt Jacob break; 134310365e5aSMatt Jacob 134410365e5aSMatt Jacob case CT7_SRR: 1345387d8239SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG0, "SRR received"); 134610365e5aSMatt Jacob break; 134710365e5aSMatt Jacob 134810365e5aSMatt Jacob default: 13492df76c16SMatt Jacob isp_prt(isp, ISP_LOGERR, "Unknown CTIO7 status 0x%x", ct->ct_nphdl); 135010365e5aSMatt Jacob break; 135110365e5aSMatt Jacob } 135210365e5aSMatt Jacob 135310365e5aSMatt Jacob if (xs == NULL) { 135410365e5aSMatt Jacob /* 135510365e5aSMatt Jacob * There may be more than one CTIO for a data transfer, 135610365e5aSMatt Jacob * or this may be a status CTIO we're not monitoring. 135710365e5aSMatt Jacob * 135810365e5aSMatt Jacob * The assumption is that they'll all be returned in the 135910365e5aSMatt Jacob * order we got them. 136010365e5aSMatt Jacob */ 136110365e5aSMatt Jacob if (ct->ct_syshandle == 0) { 136210365e5aSMatt Jacob if (ct->ct_flags & CT7_TERMINATE) { 1363387d8239SMatt Jacob isp_prt(isp, ISP_LOGINFO, "termination of [RX_ID 0x%x] complete", ct->ct_rxid); 136410365e5aSMatt Jacob } else if ((ct->ct_flags & CT7_SENDSTATUS) == 0) { 13652df76c16SMatt Jacob isp_prt(isp, pl, "intermediate CTIO completed ok"); 136610365e5aSMatt Jacob } else { 13672df76c16SMatt Jacob isp_prt(isp, pl, "unmonitored CTIO completed ok"); 136810365e5aSMatt Jacob } 136910365e5aSMatt Jacob } else { 13702df76c16SMatt Jacob isp_prt(isp, pl, "NO xs for CTIO (handle 0x%x) status 0x%x", ct->ct_syshandle, ct->ct_nphdl); 137110365e5aSMatt Jacob } 137210365e5aSMatt Jacob } else { 13732df76c16SMatt Jacob if ((ct->ct_flags & CT7_DATAMASK) != CT7_NO_DATA) { 137410365e5aSMatt Jacob ISP_DMAFREE(isp, xs, ct->ct_syshandle); 137510365e5aSMatt Jacob } 13762df76c16SMatt Jacob if (ct->ct_flags & CT7_SENDSTATUS) { 137710365e5aSMatt Jacob /* 137810365e5aSMatt Jacob * Sent status and command complete. 137910365e5aSMatt Jacob * 138010365e5aSMatt Jacob * We're now really done with this command, so we 138110365e5aSMatt Jacob * punt to the platform dependent layers because 138210365e5aSMatt Jacob * only there can we do the appropriate command 138310365e5aSMatt Jacob * complete thread synchronization. 138410365e5aSMatt Jacob */ 138510365e5aSMatt Jacob isp_prt(isp, pl, "status CTIO complete"); 138610365e5aSMatt Jacob } else { 138710365e5aSMatt Jacob /* 138810365e5aSMatt Jacob * Final CTIO completed. Release DMA resources and 138910365e5aSMatt Jacob * notify platform dependent layers. 139010365e5aSMatt Jacob */ 139110365e5aSMatt Jacob isp_prt(isp, pl, "data CTIO complete"); 139210365e5aSMatt Jacob } 13932df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_ACTION, ct); 139410365e5aSMatt Jacob /* 139510365e5aSMatt Jacob * The platform layer will destroy the handle if appropriate. 139610365e5aSMatt Jacob */ 139710365e5aSMatt Jacob } 139810365e5aSMatt Jacob } 13992df76c16SMatt Jacob 14002df76c16SMatt Jacob static void 14012df76c16SMatt Jacob isp_handle_24xx_inotify(ispsoftc_t *isp, in_fcentry_24xx_t *inot_24xx) 14022df76c16SMatt Jacob { 14032df76c16SMatt Jacob uint8_t ochan, chan, lochan, hichan; 14042df76c16SMatt Jacob 14052df76c16SMatt Jacob /* 14062df76c16SMatt Jacob * Check to see whether we got a wildcard channel. 14072df76c16SMatt Jacob * If so, we have to iterate over all channels. 14082df76c16SMatt Jacob */ 14092df76c16SMatt Jacob ochan = chan = ISP_GET_VPIDX(isp, inot_24xx->in_vpidx); 14102df76c16SMatt Jacob if (chan == 0xff) { 14112df76c16SMatt Jacob lochan = 0; 14122df76c16SMatt Jacob hichan = isp->isp_nchan; 14132df76c16SMatt Jacob } else { 14142df76c16SMatt Jacob if (chan >= isp->isp_nchan) { 14152df76c16SMatt Jacob char buf[64]; 14162df76c16SMatt Jacob ISP_SNPRINTF(buf, sizeof buf, "%s: bad channel %d for status 0x%x", __func__, chan, inot_24xx->in_status); 14172df76c16SMatt Jacob isp_print_bytes(isp, buf, QENTRY_LEN, inot_24xx); 1418387d8239SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot_24xx); 14192df76c16SMatt Jacob return; 14202df76c16SMatt Jacob } 14212df76c16SMatt Jacob lochan = chan; 14222df76c16SMatt Jacob hichan = chan + 1; 14232df76c16SMatt Jacob } 14242df76c16SMatt Jacob isp_prt(isp, ISP_LOGTDEBUG1, "%s: Immediate Notify Channels %d..%d status=0x%x seqid=0x%x", __func__, lochan, hichan-1, inot_24xx->in_status, inot_24xx->in_rxid); 14252df76c16SMatt Jacob for (chan = lochan; chan < hichan; chan++) { 142633d34744SAlexander Motin if (FCPARAM(isp, chan)->role == ISP_ROLE_NONE) 142733d34744SAlexander Motin continue; 14282df76c16SMatt Jacob switch (inot_24xx->in_status) { 14292df76c16SMatt Jacob case IN24XX_LIP_RESET: 14302df76c16SMatt Jacob case IN24XX_LINK_RESET: 14312df76c16SMatt Jacob case IN24XX_PORT_LOGOUT: 14322df76c16SMatt Jacob case IN24XX_PORT_CHANGED: 14332df76c16SMatt Jacob case IN24XX_LINK_FAILED: 14342df76c16SMatt Jacob case IN24XX_SRR_RCVD: 14352df76c16SMatt Jacob case IN24XX_ELS_RCVD: 1436387d8239SMatt Jacob inot_24xx->in_reserved = 0; /* clear this for later usage */ 14372df76c16SMatt Jacob inot_24xx->in_vpidx = chan; 14382df76c16SMatt Jacob isp_async(isp, ISPASYNC_TARGET_ACTION, inot_24xx); 14392df76c16SMatt Jacob break; 14402df76c16SMatt Jacob default: 14412df76c16SMatt Jacob isp_prt(isp, ISP_LOGINFO, "%s: unhandled status (0x%x) for chan %d", __func__, inot_24xx->in_status, chan); 1442387d8239SMatt Jacob isp_async(isp, ISPASYNC_TARGET_NOTIFY_ACK, inot_24xx); 14432df76c16SMatt Jacob break; 14442df76c16SMatt Jacob } 14452df76c16SMatt Jacob } 14462df76c16SMatt Jacob inot_24xx->in_vpidx = ochan; 14472df76c16SMatt Jacob } 1448ea49c6e4SMatt Jacob #endif 1449