ql_iocb.c revision fcf3ce441efd61da9bb2884968af01cb7c1452cc
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/* Copyright 2008 QLogic Corporation */
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "Copyright 2008 QLogic Corporation; ql_iocb.c"
/*
* ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
*
* ***********************************************************************
* * **
* * NOTICE **
* * COPYRIGHT (C) 1996-2008 QLOGIC CORPORATION **
* * ALL RIGHTS RESERVED **
* * **
* ***********************************************************************
*
*/
#include <ql_apps.h>
#include <ql_api.h>
#include <ql_debug.h>
#include <ql_iocb.h>
#include <ql_isr.h>
#include <ql_xioctl.h>
/*
* Local Function Prototypes.
*/
static void ql_isp24xx_rcvbuf(ql_adapter_state_t *);
/*
* ql_start_iocb
* The start IOCB is responsible for building request packets
* on request ring and modifying ISP input pointer.
*
* Input:
* ha: adapter state pointer.
* sp: srb structure pointer.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* Acquire ring lock. */
/*
* Start any pending ones before this one.
* Add command to pending command queue if not empty.
*/
/* Remove command from pending command queue */
}
} else {
/* Get command from pending command queue if not empty. */
/* Release ring specific lock */
return;
}
/* Remove command from pending command queue */
}
/* start as many as possible */
for (;;) {
/* Calculate number of free request entries. */
} else {
}
}
/* If no room for request in request ring. */
" req_q_cnt=%d, req_ring_index=%d\n",
ha->req_ring_index);
break;
}
}
/* Check for room in outstanding command list. */
}
break;
}
}
if (cnt == MAX_OUTSTANDING_COMMANDS) {
break;
}
/* If room for request in request ring. */
/* Zero out packet. */
/* Setup IOCB common data. */
/* Setup remaining IOCB data. */
/* Sync DMA buffer. */
/* Adjust ring index. */
ha->req_ring_index++;
ha->req_ring_index = 0;
} else {
ha->request_ring_ptr++;
}
/* Reset watchdog timer */
/* Set chip new ring index. */
/* Update outstanding command count statistic. */
break;
}
/* Remove command from pending command queue */
}
/* Release ring specific lock */
}
/*
* ql_req_pkt
* Function is responsible for locking ring and
* getting a zeroed out request packet.
*
* Input:
* ha: adapter state pointer.
* pkt: address for packet pointer.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
int
{
int rval = QL_FUNCTION_TIMEOUT;
/* Wait for 30 seconds for slot. */
/* Acquire ring lock. */
/* Calculate number of free request entries. */
} else {
}
}
}
/* Found empty request ring slot? */
/* Zero out packet. */
*long_ptr++ = 0;
}
/* Setup IOCB common data. */
rval = QL_SUCCESS;
break;
}
/* Release request queue lock. */
/* Check for pending interrupts. */
/*
* XXX protect interrupt routine from calling itself.
* Need to revisit this routine. So far we never
* hit this case as req slot was available
*/
}
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_isp_cmd
* Function is responsible for modifying ISP input pointer.
* Releases ring lock.
*
* Input:
* ha: adapter state pointer.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* Sync DMA buffer. */
/* Adjust ring index. */
ha->req_ring_index++;
ha->req_ring_index = 0;
} else {
ha->request_ring_ptr++;
}
/* Set chip new ring index. */
/* Release ring lock. */
}
/*
* ql_command_iocb
* Setup of command IOCB.
*
* Input:
* ha: adapter state pointer.
* sp: srb structure pointer.
*
* arg: request queue packet.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* Set LUN number */
/* Set target ID */
} else {
}
/* Set tag queue control flags */
/* else if (fcp->fcp_cntl.cntl_qtype == FCP_QTYPE_SIMPLE) */
} else {
}
/* Set ISP command timeout. */
/* Load SCSI CDB */
} else {
}
if (fcp->fcp_data_len == 0) {
return;
}
/*
* Set transfer direction. Load Data segments.
*/
}
/* Set data segment count. */
/* Load total byte count. */
/* Load command data segment. */
cp->dmac_notused);
}
seg_cnt--;
cnt--;
cp++;
}
/*
* Build continuation packets.
*/
if (seg_cnt) {
}
}
/*
* ql_continuation_iocb
* Setup of continuation IOCB.
*
* Input:
* ha: adapter state pointer.
* cp: cookie list pointer.
* seg_cnt: number of segments.
* addr64: 64 bit addresses.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static void
{
/*
* Build continuation packets.
*/
while (seg_cnt) {
/* Sync DMA buffer. */
/* Adjust ring pointer, and deal with wrap. */
ha->req_ring_index++;
ha->req_ring_index = 0;
} else {
ha->request_ring_ptr++;
}
/* Zero out packet. */
/*
* Build continuation packet.
*/
if (addr64) {
cp->dmac_address);
cp->dmac_notused);
seg_cnt--;
cnt--;
cp++;
}
} else {
cp->dmac_address);
seg_cnt--;
cnt--;
cp++;
}
}
}
}
/*
* ql_command_24xx_iocb
* Setup of ISP24xx command IOCB.
*
* Input:
* ha: adapter state pointer.
* sp: srb structure pointer.
* arg: request queue packet.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* Set LUN number */
/* Set N_port handle */
/* Set target ID */
/* Set ISP command timeout. */
sp->isp_timeout);
}
/* Load SCSI CDB */
}
/*
* Set tag queue control flags
* Note:
* Cannot copy fcp->fcp_cntl.cntl_qtype directly,
* problem with x86 in 32bit kernel mode
*/
case FCP_QTYPE_SIMPLE:
break;
case FCP_QTYPE_HEAD_OF_Q:
break;
case FCP_QTYPE_ORDERED:
break;
case FCP_QTYPE_ACA_Q_TAG:
break;
case FCP_QTYPE_UNTAGGED:
break;
default:
break;
}
if (fcp->fcp_data_len == 0) {
return;
}
/* Set transfer direction. */
}
/* Set data segment count. */
/* Load total byte count. */
fcp->fcp_data_len);
/* Load command data segment. */
seg_cnt--;
cp++;
/*
* Build continuation packets.
*/
if (seg_cnt) {
}
}
/*
* ql_marker
* Function issues marker IOCB.
*
* Input:
* ha: adapter state pointer.
* loop_id: device loop ID
* lun: device LUN
* type: marker modifier
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
int
{
int rval;
if (rval == QL_SUCCESS) {
/* Set LUN number */
/* Set N_port handle */
} else {
} else {
}
}
/* Issue command to ISP */
ql_isp_cmd(ha);
}
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_ms_iocb
* Setup of name/management server IOCB.
*
* Input:
* ha = adapter state pointer.
* sp = srb structure pointer.
* arg = request queue packet.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
#if 0
#endif
/*
* Build command packet.
*/
/* Set loop ID */
} else {
}
/* Set ISP command timeout. */
/* Set cmd data segment count. */
/* Set total data segment count */
/* Load ct cmd byte count. */
/* Load ct rsp byte count. */
/* Load MS command data segments. */
seg_cnt--;
/* Load MS response entry data segments. */
seg_cnt--;
cp++;
/*
* Build continuation packets.
*/
if (seg_cnt) {
}
}
/*
* ql_ms_24xx_iocb
* Setup of name/management server IOCB.
*
* Input:
* ha: adapter state pointer.
* sp: srb structure pointer.
* arg: request queue packet.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
#if 0
#endif
/*
* Build command packet.
*/
/* Set loop ID */
/* Set ISP command timeout. */
sp->isp_timeout);
}
/* Load ct cmd byte count. */
/* Load ct rsp byte count. */
/* Load MS command entry data segments. */
/* Load MS response entry data segments. */
seg_cnt--;
cp++;
/*
* Build continuation packets.
*/
if (seg_cnt) {
}
}
/*
* ql_ip_iocb
* Setup of IP IOCB.
*
* Input:
* ha: adapter state pointer.
* sp: srb structure pointer.
* arg: request queue packet.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* Set loop ID */
} else {
}
/* Set control flags */
}
/* Set ISP command timeout. */
/* Set data segment count. */
/* Load total byte count. */
/*
* Build command packet.
*/
} else {
}
/* Load command entry data segments. */
cp->dmac_notused);
}
seg_cnt--;
cnt--;
cp++;
}
/*
* Build continuation packets.
*/
if (seg_cnt) {
}
}
/*
* ql_ip_24xx_iocb
* Setup of IP IOCB for ISP24xx.
*
* Input:
* ha: adapter state pointer.
* sp: srb structure pointer.
* arg: request queue packet.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* Set N_port handle */
/* Set ISP command timeout. */
sp->isp_timeout);
}
/* Set data segment count. */
/* Load total byte count. */
/* Set control flags */
/* Set frame header control flags */
/* Load command data segment. */
seg_cnt--;
cp++;
/*
* Build continuation packets.
*/
if (seg_cnt) {
}
}
/*
* ql_isp_rcvbuf
* Locates free buffers and places it on the receive buffer queue.
*
* Input:
* ha = adapter state pointer.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
int debounce_count = QL_MAX_DEBOUNCE;
int ring_updated = FALSE;
return;
}
/* Acquire adapter state lock. */
/* Calculate number of free receive buffer entries. */
do {
break;
} else {
}
} while (debounce_count --);
if (debounce_count < 0) {
/* This should never happen */
}
if (rcv_q_cnt == RCVBUF_CONTAINER_CNT) {
rcv_q_cnt--;
}
/* Load all free buffers in ISP receive buffer ring. */
index = 0;
/* Locate a buffer to give. */
QL_UB_LOCK(ha);
while (index < QL_UB_LIMIT) {
SRB_UB_ACQUIRED)))) {
break;
}
}
index++;
}
if (index < QL_UB_LIMIT) {
rcv_q_cnt--;
index++;
/*
* Build container.
*/
/* Adjust ring index. */
ha->rcvbuf_ring_index++;
ha->rcvbuf_ring_index = 0;
} else {
ha->rcvbuf_ring_ptr++;
}
ring_updated = TRUE;
}
}
if (ring_updated) {
/* Sync queue. */
/* Set chip new ring index. */
}
/* Release adapter state lock. */
}
/*
* ql_isp24xx_rcvbuf
* Locates free buffers and send it to adapter.
*
* Input:
* ha = adapter state pointer.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
static void
{
int rval;
for (;;) {
/* Locate a buffer to give. */
QL_UB_LOCK(ha);
SRB_UB_ACQUIRED)))) {
break;
}
}
}
if (index == QL_UB_LIMIT) {
break;
}
/* Get IOCB packet for buffers. */
if (rval != QL_SUCCESS) {
QL_UB_LOCK(ha);
break;
}
}
/*
* Build container.
*/
pkt->buffer_count++;
container++;
ql_isp_cmd(ha);
}
}
ql_isp_cmd(ha);
}
}
/*
* ql_modify_lun
* Function enables, modifies or disables ISP to respond as a target.
*
* Input:
* ha = adapter state pointer.
* count = number buffers for incoming commands.
*
* Returns:
* ql local function return status code.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
int
{
int rval = QL_SUCCESS;
/*
* Count the number of SCSI unsolicited buffers, that have been
* allocated.
*/
ubcount = 0;
QL_UB_LOCK(ha);
ubcount++;
}
}
}
return (rval);
}
if (ubcount == 0) {
/* Disable the target mode Luns */
ha->ub_command_count = 0;
ha->ub_notify_count = 0;
pkt->command_count = 0;
pkt->immediate_notify_count = 0;
} else {
/* Modify the command count for target mode */
/*
* calculate the new value of command count
* and notify count and then issue the command
* to change the values in the firmware.
*/
if (ubcount < 255) {
/* Save one for immediate notify. */
if (ubcount > 1) {
} else {
}
notify_count = 1;
} else {
cmd_count = 255;
notify_count = (uint8_t)
(ubcount - 255);
} else {
notify_count = 255;
}
}
/* cmd_count value increased */
(uint8_t)(notify_count -
} else if (notify_count <
ha->ub_notify_count) {
}
} else {
/* cmd_count value reduced */
if (ml_pkt->command_count != 0) {
}
(uint8_t)(notify_count -
} else if (notify_count <
ha->ub_notify_count) {
}
}
}
} else {
/* Enable the Luns for the target mode */
if (ubcount < 255) {
/* Save one for immediate notify. */
if (ubcount > 1) {
} else {
}
} else {
} else {
}
}
}
/* Issue command to ISP */
ql_isp_cmd(ha);
if (rval != QL_SUCCESS) {
} else {
/*EMPTY*/
}
return (rval);
}
/*
* ql_notify_acknowledge_iocb
* Setup of notify acknowledge IOCB for pending
* immediate notify entry.
*
* Input:
* ha: adapter state pointer.
* cmd: target command context pointer.
* pkt: request queue packet.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
/* Handle LIP reset event. */
}
}
/*
* ql_continue_target_io_iocb
* Setup of continue target I/O IOCB for pending
* accept target I/O entry.
*
* Input:
* ha = adapter state pointer.
* sp = srb structure pointer.
* arg = request queue packet.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
void
{
return;
}
} else {
}
/* Set ISP command timeout. */
sp->isp_timeout);
}
}
/* Set relative offset. */
} else {
/* (sp->flags & SRB_FCP_RSP_PKT) */
}
/*
* Load data segments.
*/
/* Transfer length. */
/* Load data segments. */
(uint32_t *)(void *)
cp->dmac_address);
(uint32_t *)(void *)
cp->dmac_notused);
(uint32_t *)(void *)
} else {
(uint32_t *)(void *)
cp->dmac_address);
(uint32_t *)(void *)
}
}
}
/*
* ql_continue_target_io_2400_iocb
* Setup of continue target I/O IOCB for pending
* accept target I/O entry.
*
* Input:
* ha = adapter state pointer.
* sp = srb structure pointer.
* arg = request queue packet.
*
* Context:
* Interrupt or Kernel context, no mailbox commands allowed.
*/
/* ARGSUSED */
void
void *arg)
{
}