#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/scsi/scsi.h>
#include <sys/note.h>
#include <sys/scsi/adapters/fasreg.h>
#include <sys/scsi/adapters/fasvar.h>
#include <sys/scsi/adapters/fascmd.h>
#include <sys/vtrace.h>
#ifdef FASDEBUG
extern int fasdebug;
extern int fasdebug_instance;
#endif
void fas_complete_arq_pkt(struct scsi_pkt *pkt);
void fas_call_pkt_comp(register struct fas *fas,
register struct fas_cmd *sp);
void fas_empty_callbackQ(struct fas *fas);
int fas_init_callbacks(struct fas *fas);
void fas_destroy_callbacks(struct fas *fas);
void fas_printf(struct fas *fas, const char *fmt, ...);
int
fas_init_callbacks(struct fas *fas)
{
mutex_init(&fas->f_c_mutex, NULL, MUTEX_DRIVER, fas->f_iblock);
return (0);
}
void
fas_destroy_callbacks(struct fas *fas)
{
mutex_destroy(&fas->f_c_mutex);
}
void
fas_empty_callbackQ(struct fas *fas)
{
register struct fas_cmd *sp;
TRACE_0(TR_FAC_SCSI, TR_FAS_EMPTY_CALLBACKQ_START,
"fas_empty_callbackQ_start");
mutex_enter(&fas->f_c_mutex);
if (fas->f_c_in_callback) {
goto done;
}
fas->f_c_in_callback = 1;
while (fas->f_c_qf) {
register struct fas_cmd *qf = fas->f_c_qf;
fas->f_c_qf = fas->f_c_qb = NULL;
mutex_exit(&fas->f_c_mutex);
while (qf) {
sp = qf;
qf = sp->cmd_forw;
(*sp->cmd_pkt->pkt_comp)(sp->cmd_pkt);
}
mutex_enter(&fas->f_c_mutex);
}
fas->f_c_in_callback = 0;
done:
mutex_exit(&fas->f_c_mutex);
TRACE_0(TR_FAC_SCSI, TR_FAS_EMPTY_CALLBACKQ_END,
"fas_empty_callbackQ_end");
}
void
fas_call_pkt_comp(register struct fas *fas, register struct fas_cmd *sp)
{
TRACE_0(TR_FAC_SCSI, TR_FAS_CALL_PKT_COMP_START,
"fas_call_pkt_comp_start");
ASSERT(sp != 0);
ASSERT((sp->cmd_flags & CFLAG_COMPLETED) == 0);
ASSERT((sp->cmd_flags & CFLAG_FREE) == 0);
ASSERT(sp->cmd_flags & CFLAG_FINISHED);
ASSERT(fas->f_ncmds >= fas->f_ndisc);
ASSERT((sp->cmd_flags & CFLAG_CMDDISC) == 0);
ASSERT(sp != fas->f_current_sp);
ASSERT(sp != fas->f_active[sp->cmd_slot]->f_slot[sp->cmd_tag[1]]);
sp->cmd_flags &= ~CFLAG_IN_TRANSPORT;
sp->cmd_flags |= CFLAG_COMPLETED;
sp->cmd_qfull_retries = 0;
if (sp->cmd_pkt->pkt_comp && !(sp->cmd_flags & CFLAG_CMDARQ)) {
if (sp->cmd_pkt->pkt_reason != CMD_CMPLT) {
IPRINTF6("completion for %d.%d, sp=0x%p, "
"reason=%s, stats=%x, state=%x\n",
Tgt(sp), Lun(sp), (void *)sp,
scsi_rname(sp->cmd_pkt->pkt_reason),
sp->cmd_pkt->pkt_statistics,
sp->cmd_pkt->pkt_state);
} else {
EPRINTF2("completion queued for %d.%dn",
Tgt(sp), Lun(sp));
}
mutex_enter(&fas->f_c_mutex);
if (fas->f_c_qf) {
register struct fas_cmd *dp = fas->f_c_qb;
ASSERT(dp != NULL);
fas->f_c_qb = sp;
sp->cmd_forw = NULL;
dp->cmd_forw = sp;
} else {
fas->f_c_qf = fas->f_c_qb = sp;
sp->cmd_forw = NULL;
}
mutex_exit(&fas->f_c_mutex);
} else if ((sp->cmd_flags & CFLAG_CMDARQ) && sp->cmd_pkt->pkt_comp) {
fas_complete_arq_pkt(sp->cmd_pkt);
} else {
EPRINTF2("No completion routine for 0x%p reason %x\n",
(void *)sp, sp->cmd_pkt->pkt_reason);
}
TRACE_0(TR_FAC_SCSI, TR_FAS_CALL_PKT_COMP_END,
"fas_call_pkt_comp_end");
}