Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fea9d6c7 authored by Volker Sameske's avatar Volker Sameske Committed by James Bottomley
Browse files

[SCSI] zfcp: improve management of request IDs



Improve request handling. Use hash table to manage request IDs.

Signed-off-by: default avatarVolker Sameske <sameske@de.ibm.com>
Signed-off-by: default avatarAndreas Herrmann <aherrman@de.ibm.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent c2602c48
Loading
Loading
Loading
Loading
+111 −9
Original line number Diff line number Diff line
@@ -112,6 +112,105 @@ _zfcp_hex_dump(char *addr, int count)
		printk("\n");
}


/****************************************************************/
/****** Functions to handle the request ID hash table    ********/
/****************************************************************/

#define ZFCP_LOG_AREA			ZFCP_LOG_AREA_FSF

static int zfcp_reqlist_init(struct zfcp_adapter *adapter)
{
	int i;

	adapter->req_list = kcalloc(REQUEST_LIST_SIZE, sizeof(struct list_head),
				    GFP_KERNEL);

	if (!adapter->req_list)
		return -ENOMEM;

	for (i=0; i<REQUEST_LIST_SIZE; i++)
		INIT_LIST_HEAD(&adapter->req_list[i]);

	return 0;
}

static void zfcp_reqlist_free(struct zfcp_adapter *adapter)
{
	struct zfcp_fsf_req *request, *tmp;
	unsigned int i;

	for (i=0; i<REQUEST_LIST_SIZE; i++) {
		if (list_empty(&adapter->req_list[i]))
			continue;

		list_for_each_entry_safe(request, tmp,
					 &adapter->req_list[i], list)
			list_del(&request->list);
	}

	kfree(adapter->req_list);
}

void zfcp_reqlist_add(struct zfcp_adapter *adapter,
		      struct zfcp_fsf_req *fsf_req)
{
	unsigned int i;

	i = fsf_req->req_id % REQUEST_LIST_SIZE;
	list_add_tail(&fsf_req->list, &adapter->req_list[i]);
}

void zfcp_reqlist_remove(struct zfcp_adapter *adapter, unsigned long req_id)
{
	struct zfcp_fsf_req *request, *tmp;
	unsigned int i, counter;
	u64 dbg_tmp[2];

	i = req_id % REQUEST_LIST_SIZE;
	BUG_ON(list_empty(&adapter->req_list[i]));

	counter = 0;
	list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list) {
		if (request->req_id == req_id) {
			dbg_tmp[0] = (u64) atomic_read(&adapter->reqs_active);
			dbg_tmp[1] = (u64) counter;
			debug_event(adapter->erp_dbf, 4, (void *) dbg_tmp, 16);
			list_del(&request->list);
			break;
		}
		counter++;
	}
}

struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *adapter,
					   unsigned long req_id)
{
	struct zfcp_fsf_req *request, *tmp;
	unsigned int i;

	i = req_id % REQUEST_LIST_SIZE;

	list_for_each_entry_safe(request, tmp, &adapter->req_list[i], list)
		if (request->req_id == req_id)
			return request;

	return NULL;
}

int zfcp_reqlist_isempty(struct zfcp_adapter *adapter)
{
	unsigned int i;

	for (i=0; i<REQUEST_LIST_SIZE; i++)
		if (!list_empty(&adapter->req_list[i]))
			return 0;

	return 1;
}

#undef ZFCP_LOG_AREA

/****************************************************************/
/************** Uncategorised Functions *************************/
/****************************************************************/
@@ -961,8 +1060,12 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
	INIT_LIST_HEAD(&adapter->port_remove_lh);

	/* initialize list of fsf requests */
	spin_lock_init(&adapter->fsf_req_list_lock);
	INIT_LIST_HEAD(&adapter->fsf_req_list_head);
	spin_lock_init(&adapter->req_list_lock);
	retval = zfcp_reqlist_init(adapter);
	if (retval) {
		ZFCP_LOG_INFO("request list initialization failed\n");
		goto failed_low_mem_buffers;
	}

	/* initialize debug locks */

@@ -1041,8 +1144,6 @@ zfcp_adapter_enqueue(struct ccw_device *ccw_device)
 *		!0 - struct zfcp_adapter  data structure could not be removed
 *			(e.g. still used)
 * locks:	adapter list write lock is assumed to be held by caller
 *              adapter->fsf_req_list_lock is taken and released within this 
 *              function and must not be held on entry
 */
void
zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
@@ -1054,14 +1155,14 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
	zfcp_sysfs_adapter_remove_files(&adapter->ccw_device->dev);
	dev_set_drvdata(&adapter->ccw_device->dev, NULL);
	/* sanity check: no pending FSF requests */
	spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
	retval = !list_empty(&adapter->fsf_req_list_head);
	spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
	if (retval) {
	spin_lock_irqsave(&adapter->req_list_lock, flags);
	retval = zfcp_reqlist_isempty(adapter);
	spin_unlock_irqrestore(&adapter->req_list_lock, flags);
	if (!retval) {
		ZFCP_LOG_NORMAL("bug: adapter %s (%p) still in use, "
				"%i requests outstanding\n",
				zfcp_get_busid_by_adapter(adapter), adapter,
				atomic_read(&adapter->fsf_reqs_active));
				atomic_read(&adapter->reqs_active));
		retval = -EBUSY;
		goto out;
	}
@@ -1087,6 +1188,7 @@ zfcp_adapter_dequeue(struct zfcp_adapter *adapter)
	zfcp_free_low_mem_buffers(adapter);
	/* free memory of adapter data structure and queues */
	zfcp_qdio_free_queues(adapter);
	zfcp_reqlist_free(adapter);
	kfree(adapter->fc_stats);
	kfree(adapter->stats_reset_data);
	ZFCP_LOG_TRACE("freeing adapter structure\n");
+5 −0
Original line number Diff line number Diff line
@@ -164,6 +164,11 @@ zfcp_ccw_set_online(struct ccw_device *ccw_device)
	retval = zfcp_adapter_scsi_register(adapter);
	if (retval)
		goto out_scsi_register;

	/* initialize request counter */
	BUG_ON(!zfcp_reqlist_isempty(adapter));
	adapter->req_no = 0;

	zfcp_erp_modify_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING,
				       ZFCP_SET);
	zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED);
+6 −5
Original line number Diff line number Diff line
@@ -887,10 +887,10 @@ struct zfcp_adapter {
						      removed */
	u32			ports;	           /* number of remote ports */
	struct timer_list	scsi_er_timer;     /* SCSI err recovery watch */
	struct list_head	fsf_req_list_head; /* head of FSF req list */
	spinlock_t		fsf_req_list_lock; /* lock for ops on list of
						      FSF requests */
        atomic_t       		fsf_reqs_active;   /* # active FSF reqs */
	atomic_t		reqs_active;	   /* # active FSF reqs */
	unsigned long		req_no;		   /* unique FSF req number */
	struct list_head	*req_list;	   /* list of pending reqs */
	spinlock_t		req_list_lock;	   /* request list lock */
	struct zfcp_qdio_queue	request_queue;	   /* request queue */
	u32			fsf_req_seq_no;	   /* FSF cmnd seq number */
	wait_queue_head_t	request_wq;	   /* can be used to wait for
@@ -986,6 +986,7 @@ struct zfcp_unit {
/* FSF request */
struct zfcp_fsf_req {
	struct list_head       list;	       /* list of FSF requests */
	unsigned long	       req_id;	       /* unique request ID */
	struct zfcp_adapter    *adapter;       /* adapter request belongs to */
	u8		       sbal_number;    /* nr of SBALs free for use */
	u8		       sbal_first;     /* first SBAL for this request */
+7 −9
Original line number Diff line number Diff line
@@ -848,18 +848,16 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
	struct zfcp_adapter *adapter = erp_action->adapter;

	if (erp_action->fsf_req) {
		/* take lock to ensure that request is not being deleted meanwhile */
		spin_lock(&adapter->fsf_req_list_lock);
		/* check whether fsf req does still exist */
		list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list)
		    if (fsf_req == erp_action->fsf_req)
			break;
		if (fsf_req && (fsf_req->erp_action == erp_action)) {
		/* take lock to ensure that request is not deleted meanwhile */
		spin_lock(&adapter->req_list_lock);
		if ((!zfcp_reqlist_ismember(adapter,
					    erp_action->fsf_req->req_id)) &&
		    (fsf_req->erp_action == erp_action)) {
			/* fsf_req still exists */
			debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
			debug_event(adapter->erp_dbf, 3, &fsf_req,
				    sizeof (unsigned long));
			/* dismiss fsf_req of timed out or dismissed erp_action */
			/* dismiss fsf_req of timed out/dismissed erp_action */
			if (erp_action->status & (ZFCP_STATUS_ERP_DISMISSED |
						  ZFCP_STATUS_ERP_TIMEDOUT)) {
				debug_text_event(adapter->erp_dbf, 3,
@@ -892,7 +890,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
			 */
			erp_action->fsf_req = NULL;
		}
		spin_unlock(&adapter->fsf_req_list_lock);
		spin_unlock(&adapter->req_list_lock);
	} else
		debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq");

+5 −1
Original line number Diff line number Diff line
@@ -63,7 +63,6 @@ extern int zfcp_qdio_allocate_queues(struct zfcp_adapter *);
extern void zfcp_qdio_free_queues(struct zfcp_adapter *);
extern int  zfcp_qdio_determine_pci(struct zfcp_qdio_queue *,
				    struct zfcp_fsf_req *);
extern int  zfcp_qdio_reqid_check(struct zfcp_adapter *, void *);

extern volatile struct qdio_buffer_element *zfcp_qdio_sbale_req
	(struct zfcp_fsf_req *, int, int);
@@ -190,5 +189,10 @@ extern void zfcp_scsi_dbf_event_abort(const char *, struct zfcp_adapter *,
				      struct zfcp_fsf_req *);
extern void zfcp_scsi_dbf_event_devreset(const char *, u8, struct zfcp_unit *,
					 struct scsi_cmnd *);
extern void zfcp_reqlist_add(struct zfcp_adapter *, struct zfcp_fsf_req *);
extern void zfcp_reqlist_remove(struct zfcp_adapter *, unsigned long);
extern struct zfcp_fsf_req *zfcp_reqlist_ismember(struct zfcp_adapter *,
						  unsigned long);
extern int zfcp_reqlist_isempty(struct zfcp_adapter *);

#endif	/* ZFCP_EXT_H */
Loading