| /****************************************************************************** | 
 |  *                  QLOGIC LINUX SOFTWARE | 
 |  * | 
 |  * QLogic ISP2x00 device driver for Linux 2.6.x | 
 |  * Copyright (C) 2003-2004 QLogic Corporation | 
 |  * (www.qlogic.com) | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or modify it | 
 |  * under the terms of the GNU General Public License as published by the | 
 |  * Free Software Foundation; either version 2, or (at your option) any | 
 |  * later version. | 
 |  * | 
 |  * This program is distributed in the hope that it will be useful, but | 
 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * General Public License for more details. | 
 |  * | 
 |  ******************************************************************************/ | 
 |  | 
 | /* Management functions for various lists */ | 
 |  | 
 | /* __add_to_done_queue() | 
 |  *  | 
 |  * Place SRB command on done queue. | 
 |  * | 
 |  * Input: | 
 |  *      ha           = host pointer | 
 |  *      sp           = srb pointer. | 
 |  * Locking: | 
 |  * 	this function assumes the ha->list_lock is already taken | 
 |  */ | 
 | static inline void  | 
 | __add_to_done_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 | 	/* | 
 |         if (sp->state != SRB_NO_QUEUE_STATE &&  | 
 |         	sp->state != SRB_ACTIVE_STATE) | 
 | 		BUG(); | 
 | 	*/ | 
 |  | 
 |         /* Place block on done queue */ | 
 |         sp->cmd->host_scribble = (unsigned char *) NULL; | 
 |         sp->state = SRB_DONE_STATE; | 
 |         list_add_tail(&sp->list,&ha->done_queue); | 
 |         ha->done_q_cnt++; | 
 | 	sp->ha = ha; | 
 | } | 
 |  | 
 | static inline void  | 
 | __add_to_retry_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 | 	/* | 
 |         if( sp->state != SRB_NO_QUEUE_STATE &&  | 
 |         	sp->state != SRB_ACTIVE_STATE) | 
 | 		BUG(); | 
 | 	*/ | 
 |  | 
 |         /* Place block on retry queue */ | 
 |         list_add_tail(&sp->list,&ha->retry_queue); | 
 |         ha->retry_q_cnt++; | 
 |         sp->flags |= SRB_WATCHDOG; | 
 |         sp->state = SRB_RETRY_STATE; | 
 | 	sp->ha = ha; | 
 | } | 
 |  | 
 | static inline void  | 
 | __add_to_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 | 	/* | 
 |         if( sp->state != SRB_NO_QUEUE_STATE &&  | 
 |         	sp->state != SRB_ACTIVE_STATE) | 
 | 		BUG(); | 
 | 	*/ | 
 |  | 
 |         /* Place block on retry queue */ | 
 |         list_add_tail(&sp->list,&ha->scsi_retry_queue); | 
 |         ha->scsi_retry_q_cnt++; | 
 |         sp->state = SRB_SCSI_RETRY_STATE; | 
 | 	sp->ha = ha; | 
 | } | 
 |  | 
 | static inline void  | 
 | add_to_done_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         unsigned long flags; | 
 |  | 
 |         spin_lock_irqsave(&ha->list_lock, flags); | 
 |         __add_to_done_queue(ha,sp); | 
 |         spin_unlock_irqrestore(&ha->list_lock, flags); | 
 | } | 
 |  | 
 | static inline void  | 
 | add_to_free_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 | 	mempool_free(sp, ha->srb_mempool); | 
 | } | 
 |  | 
 | static inline void  | 
 | add_to_retry_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         unsigned long flags; | 
 |  | 
 |         spin_lock_irqsave(&ha->list_lock, flags); | 
 |         __add_to_retry_queue(ha,sp); | 
 |         spin_unlock_irqrestore(&ha->list_lock, flags); | 
 | } | 
 |  | 
 | static inline void  | 
 | add_to_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         unsigned long flags; | 
 |  | 
 |         spin_lock_irqsave(&ha->list_lock, flags); | 
 |         __add_to_scsi_retry_queue(ha,sp); | 
 |         spin_unlock_irqrestore(&ha->list_lock, flags); | 
 | } | 
 |  | 
 | /* | 
 |  * __del_from_retry_queue | 
 |  *      Function used to remove a command block from the | 
 |  *      watchdog timer queue. | 
 |  * | 
 |  *      Note: Must insure that command is on watchdog | 
 |  *            list before calling del_from_retry_queue | 
 |  *            if (sp->flags & SRB_WATCHDOG) | 
 |  * | 
 |  * Input:  | 
 |  *      ha = adapter block pointer. | 
 |  *      sp = srb pointer. | 
 |  * Locking: | 
 |  *	this function assumes the list_lock is already taken | 
 |  */ | 
 | static inline void  | 
 | __del_from_retry_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         list_del_init(&sp->list); | 
 |  | 
 |         sp->flags &= ~(SRB_WATCHDOG | SRB_BUSY); | 
 |         sp->state = SRB_NO_QUEUE_STATE; | 
 |         ha->retry_q_cnt--; | 
 | } | 
 |  | 
 | /* | 
 |  * __del_from_scsi_retry_queue | 
 |  *      Function used to remove a command block from the | 
 |  *      scsi retry queue. | 
 |  * | 
 |  * Input:  | 
 |  *      ha = adapter block pointer. | 
 |  *      sp = srb pointer. | 
 |  * Locking: | 
 |  *	this function assumes the list_lock is already taken | 
 |  */ | 
 | static inline void  | 
 | __del_from_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         list_del_init(&sp->list); | 
 |  | 
 |         ha->scsi_retry_q_cnt--; | 
 |         sp->state = SRB_NO_QUEUE_STATE; | 
 | } | 
 |  | 
 | /* | 
 |  * del_from_retry_queue | 
 |  *      Function used to remove a command block from the | 
 |  *      watchdog timer queue. | 
 |  * | 
 |  *      Note: Must insure that command is on watchdog | 
 |  *            list before calling del_from_retry_queue | 
 |  *            if (sp->flags & SRB_WATCHDOG) | 
 |  * | 
 |  * Input:  | 
 |  *      ha = adapter block pointer. | 
 |  *      sp = srb pointer. | 
 |  * Locking: | 
 |  *	this function takes and releases the list_lock | 
 |  */ | 
 | static inline void  | 
 | del_from_retry_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         unsigned long flags; | 
 |  | 
 |         /*	if (unlikely(!(sp->flags & SRB_WATCHDOG))) | 
 |         		BUG();*/ | 
 |         spin_lock_irqsave(&ha->list_lock, flags); | 
 |  | 
 |         /*	if (unlikely(list_empty(&ha->retry_queue))) | 
 |         		BUG();*/ | 
 |  | 
 |         __del_from_retry_queue(ha,sp); | 
 |  | 
 |         spin_unlock_irqrestore(&ha->list_lock, flags); | 
 | } | 
 | /* | 
 |  * del_from_scsi_retry_queue | 
 |  *      Function used to remove a command block from the | 
 |  *      scsi retry queue. | 
 |  * | 
 |  * Input:  | 
 |  *      ha = adapter block pointer. | 
 |  *      sp = srb pointer. | 
 |  * Locking: | 
 |  *	this function takes and releases the list_lock | 
 |  */ | 
 | static inline void  | 
 | del_from_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         unsigned long flags; | 
 |  | 
 |         spin_lock_irqsave(&ha->list_lock, flags); | 
 |  | 
 |         /*	if (unlikely(list_empty(&ha->scsi_retry_queue))) | 
 |         		BUG();*/ | 
 |  | 
 |         __del_from_scsi_retry_queue(ha,sp); | 
 |  | 
 |         spin_unlock_irqrestore(&ha->list_lock, flags); | 
 | } | 
 |  | 
 | /* | 
 |  * __add_to_pending_queue | 
 |  *      Add the standard SCB job to the bottom of standard SCB commands. | 
 |  * | 
 |  * Input: | 
 |  * COMPLETE!!! | 
 |  *      q  = SCSI LU pointer. | 
 |  *      sp = srb pointer. | 
 |  *      SCSI_LU_Q lock must be already obtained. | 
 |  */ | 
 | static inline int  | 
 | __add_to_pending_queue(struct scsi_qla_host *ha, srb_t * sp) | 
 | { | 
 | 	int	empty; | 
 | 	/* | 
 |         if( sp->state != SRB_NO_QUEUE_STATE && | 
 |         	sp->state != SRB_FREE_STATE && | 
 |         	sp->state != SRB_ACTIVE_STATE) | 
 | 		BUG(); | 
 | 	*/ | 
 |  | 
 | 	empty = list_empty(&ha->pending_queue); | 
 | 	list_add_tail(&sp->list, &ha->pending_queue); | 
 | 	ha->qthreads++; | 
 | 	sp->state = SRB_PENDING_STATE; | 
 |  | 
 | 	return (empty); | 
 | } | 
 |  | 
 | static inline void  | 
 | __add_to_pending_queue_head(struct scsi_qla_host *ha, srb_t * sp) | 
 | { | 
 | 	/* | 
 |         if( sp->state != SRB_NO_QUEUE_STATE &&  | 
 |         	sp->state != SRB_FREE_STATE && | 
 |         	sp->state != SRB_ACTIVE_STATE) | 
 | 		BUG(); | 
 | 	*/ | 
 |  | 
 | 	list_add(&sp->list, &ha->pending_queue); | 
 | 	ha->qthreads++; | 
 | 	sp->state = SRB_PENDING_STATE; | 
 | } | 
 |  | 
 | static inline int | 
 | add_to_pending_queue(struct scsi_qla_host *ha, srb_t *sp) | 
 | { | 
 | 	int	empty; | 
 | 	unsigned long flags; | 
 |  | 
 | 	spin_lock_irqsave(&ha->list_lock, flags); | 
 | 	empty = __add_to_pending_queue(ha, sp); | 
 | 	spin_unlock_irqrestore(&ha->list_lock, flags); | 
 |  | 
 | 	return (empty); | 
 | } | 
 | static inline void | 
 | add_to_pending_queue_head(struct scsi_qla_host *ha, srb_t *sp) | 
 | { | 
 | 	unsigned long flags; | 
 |  | 
 | 	spin_lock_irqsave(&ha->list_lock, flags); | 
 | 	__add_to_pending_queue_head(ha, sp); | 
 | 	spin_unlock_irqrestore(&ha->list_lock, flags); | 
 | } | 
 |  | 
 | static inline void | 
 | __del_from_pending_queue(struct scsi_qla_host *ha, srb_t *sp) | 
 | { | 
 | 	list_del_init(&sp->list); | 
 | 	ha->qthreads--; | 
 | 	sp->state = SRB_NO_QUEUE_STATE; | 
 | } | 
 |  | 
 | /* | 
 |  * Failover Stuff. | 
 |  */ | 
 | static inline void | 
 | __add_to_failover_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 | 	/* | 
 |         if( sp->state != SRB_NO_QUEUE_STATE &&  | 
 |         	sp->state != SRB_ACTIVE_STATE) | 
 | 		BUG(); | 
 | 	*/ | 
 |  | 
 |         list_add_tail(&sp->list,&ha->failover_queue); | 
 |         ha->failover_cnt++; | 
 |         sp->state = SRB_FAILOVER_STATE; | 
 | 	sp->ha = ha; | 
 | } | 
 |  | 
 | static inline void add_to_failover_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         unsigned long flags; | 
 |  | 
 |         spin_lock_irqsave(&ha->list_lock, flags); | 
 |  | 
 |         __add_to_failover_queue(ha,sp); | 
 |  | 
 |         spin_unlock_irqrestore(&ha->list_lock, flags); | 
 | } | 
 | static inline void __del_from_failover_queue(struct scsi_qla_host * ha, srb_t * | 
 |                 sp) | 
 | { | 
 |         ha->failover_cnt--; | 
 |         list_del_init(&sp->list); | 
 |         sp->state = SRB_NO_QUEUE_STATE; | 
 | } | 
 |  | 
 | static inline void del_from_failover_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         unsigned long flags; | 
 |  | 
 |         spin_lock_irqsave(&ha->list_lock, flags); | 
 |  | 
 |         __del_from_failover_queue(ha,sp); | 
 |  | 
 |         spin_unlock_irqrestore(&ha->list_lock, flags); | 
 | } | 
 |  | 
 | static inline void  | 
 | del_from_pending_queue(struct scsi_qla_host * ha, srb_t * sp) | 
 | { | 
 |         unsigned long flags; | 
 |  | 
 |         spin_lock_irqsave(&ha->list_lock, flags); | 
 |  | 
 |         __del_from_pending_queue(ha,sp); | 
 |  | 
 |         spin_unlock_irqrestore(&ha->list_lock, flags); | 
 | } |