#include "zfcp_ext.h"
-static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
+static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get
(struct zfcp_qdio_queue *, int, int);
static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp
(struct zfcp_fsf_req *, int, int);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
+static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
(struct zfcp_fsf_req *, unsigned long);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
+static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
(struct zfcp_fsf_req *, unsigned long);
-static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
+static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *);
-static inline void zfcp_qdio_sbale_fill
+static void zfcp_qdio_sbale_fill
(struct zfcp_fsf_req *, unsigned long, void *, int);
-static inline int zfcp_qdio_sbals_from_segment
+static int zfcp_qdio_sbals_from_segment
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
-static inline int zfcp_qdio_sbals_from_buffer
+static int zfcp_qdio_sbals_from_buffer
(struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
static qdio_handler_t zfcp_qdio_request_handler;
#define ZFCP_LOG_AREA ZFCP_LOG_AREA_QDIO
/*
- * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t
- * array in the adapter struct.
- * Cur_buf is the pointer array and count can be any number of required
- * buffers, the page-fitting arithmetic is done entirely within this funciton.
+ * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array
+ * in the adapter struct sbuf is the pointer array.
*
- * returns: number of buffers allocated
* locks: must only be called with zfcp_data.config_sema taken
*/
-static int
-zfcp_qdio_buffers_enqueue(struct qdio_buffer **cur_buf, int count)
+static void
+zfcp_qdio_buffers_dequeue(struct qdio_buffer **sbuf)
{
- int buf_pos;
- int qdio_buffers_per_page;
- int page_pos = 0;
- struct qdio_buffer *first_in_page = NULL;
-
- qdio_buffers_per_page = PAGE_SIZE / sizeof (struct qdio_buffer);
- ZFCP_LOG_TRACE("buffers_per_page=%d\n", qdio_buffers_per_page);
-
- for (buf_pos = 0; buf_pos < count; buf_pos++) {
- if (page_pos == 0) {
- cur_buf[buf_pos] = (struct qdio_buffer *)
- get_zeroed_page(GFP_KERNEL);
- if (cur_buf[buf_pos] == NULL) {
- ZFCP_LOG_INFO("error: allocation of "
- "QDIO buffer failed \n");
- goto out;
- }
- first_in_page = cur_buf[buf_pos];
- } else {
- cur_buf[buf_pos] = first_in_page + page_pos;
+ int pos;
- }
- /* was initialised to zero */
- page_pos++;
- page_pos %= qdio_buffers_per_page;
- }
- out:
- return buf_pos;
+ for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE)
+ free_page((unsigned long) sbuf[pos]);
}
/*
- * Frees BUFFER memory for each of the pointers of the struct qdio_buffer array
- * in the adapter struct cur_buf is the pointer array and count can be any
- * number of buffers in the array that should be freed starting from buffer 0
+ * Allocates BUFFER memory to each of the pointers of the qdio_buffer_t
+ * array in the adapter struct.
+ * Cur_buf is the pointer array
*
+ * returns: zero on success else -ENOMEM
* locks: must only be called with zfcp_data.config_sema taken
*/
-static void
-zfcp_qdio_buffers_dequeue(struct qdio_buffer **cur_buf, int count)
+static int
+zfcp_qdio_buffers_enqueue(struct qdio_buffer **sbuf)
{
- int buf_pos;
- int qdio_buffers_per_page;
-
- qdio_buffers_per_page = PAGE_SIZE / sizeof (struct qdio_buffer);
- ZFCP_LOG_TRACE("buffers_per_page=%d\n", qdio_buffers_per_page);
+ int pos;
- for (buf_pos = 0; buf_pos < count; buf_pos += qdio_buffers_per_page)
- free_page((unsigned long) cur_buf[buf_pos]);
- return;
+ for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos += QBUFF_PER_PAGE) {
+ sbuf[pos] = (struct qdio_buffer *) get_zeroed_page(GFP_KERNEL);
+ if (!sbuf[pos]) {
+ zfcp_qdio_buffers_dequeue(sbuf);
+ return -ENOMEM;
+ }
+ }
+ for (pos = 0; pos < QDIO_MAX_BUFFERS_PER_Q; pos++)
+ if (pos % QBUFF_PER_PAGE)
+ sbuf[pos] = sbuf[pos - 1] + 1;
+ return 0;
}
/* locks: must only be called with zfcp_data.config_sema taken */
int
zfcp_qdio_allocate_queues(struct zfcp_adapter *adapter)
{
- int buffer_count;
- int retval = 0;
+ int ret;
- buffer_count =
- zfcp_qdio_buffers_enqueue(&(adapter->request_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
- if (buffer_count < QDIO_MAX_BUFFERS_PER_Q) {
- ZFCP_LOG_DEBUG("only %d QDIO buffers allocated for request "
- "queue\n", buffer_count);
- zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
- buffer_count);
- retval = -ENOMEM;
- goto out;
- }
-
- buffer_count =
- zfcp_qdio_buffers_enqueue(&(adapter->response_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
- if (buffer_count < QDIO_MAX_BUFFERS_PER_Q) {
- ZFCP_LOG_DEBUG("only %d QDIO buffers allocated for response "
- "queue", buffer_count);
- zfcp_qdio_buffers_dequeue(&(adapter->response_queue.buffer[0]),
- buffer_count);
- ZFCP_LOG_TRACE("freeing request_queue buffers\n");
- zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
- retval = -ENOMEM;
- goto out;
- }
- out:
- return retval;
+ ret = zfcp_qdio_buffers_enqueue(adapter->request_queue.buffer);
+ if (ret)
+ return ret;
+ return zfcp_qdio_buffers_enqueue(adapter->response_queue.buffer);
}
/* locks: must only be called with zfcp_data.config_sema taken */
zfcp_qdio_free_queues(struct zfcp_adapter *adapter)
{
ZFCP_LOG_TRACE("freeing request_queue buffers\n");
- zfcp_qdio_buffers_dequeue(&(adapter->request_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
+ zfcp_qdio_buffers_dequeue(adapter->request_queue.buffer);
ZFCP_LOG_TRACE("freeing response_queue buffers\n");
- zfcp_qdio_buffers_dequeue(&(adapter->response_queue.buffer[0]),
- QDIO_MAX_BUFFERS_PER_Q);
+ zfcp_qdio_buffers_dequeue(adapter->response_queue.buffer);
}
int
* returns: error flag
*
*/
-static inline int
+static int
zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
unsigned int qdio_error, unsigned int siga_error,
int first_element, int elements_processed)
* Since we have been using this adapter, it is save to assume
* that it is not failed but recoverable. The card seems to
* report link-up events by self-initiated queue shutdown.
- * That is why we need to clear the the link-down flag
+ * That is why we need to clear the link-down flag
* which is set again in case we have missed by a mile.
*/
zfcp_erp_adapter_reopen(
return;
}
+/**
+ * zfcp_qdio_reqid_check - checks for valid reqids.
+ */
+static void zfcp_qdio_reqid_check(struct zfcp_adapter *adapter,
+ unsigned long req_id)
+{
+ struct zfcp_fsf_req *fsf_req;
+ unsigned long flags;
+
+ debug_long_event(adapter->erp_dbf, 4, req_id);
+
+ spin_lock_irqsave(&adapter->req_list_lock, flags);
+ fsf_req = zfcp_reqlist_find(adapter, req_id);
+
+ if (!fsf_req)
+ /*
+ * Unknown request means that we have potentially memory
+ * corruption and must stop the machine immediatly.
+ */
+ panic("error: unknown request id (%ld) on adapter %s.\n",
+ req_id, zfcp_get_busid_by_adapter(adapter));
+
+ zfcp_reqlist_remove(adapter, fsf_req);
+ atomic_dec(&adapter->reqs_active);
+ spin_unlock_irqrestore(&adapter->req_list_lock, flags);
+
+ /* finish the FSF request */
+ zfcp_fsf_req_complete(fsf_req);
+}
+
/*
* function: zfcp_qdio_response_handler
*
/* look for QDIO request identifiers in SB */
buffere = &buffer->element[buffere_index];
- retval = zfcp_qdio_reqid_check(adapter,
- (void *) buffere->addr);
-
- if (retval) {
- ZFCP_LOG_NORMAL("bug: unexpected inbound "
- "packet on adapter %s "
- "(reqid=0x%lx, "
- "first_element=%d, "
- "elements_processed=%d)\n",
- zfcp_get_busid_by_adapter(adapter),
- (unsigned long) buffere->addr,
- first_element,
- elements_processed);
- ZFCP_LOG_NORMAL("hex dump of inbound buffer "
- "at address %p "
- "(buffer_index=%d, "
- "buffere_index=%d)\n", buffer,
- buffer_index, buffere_index);
- ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_NORMAL,
- (char *) buffer, SBAL_SIZE);
- }
+ zfcp_qdio_reqid_check(adapter,
+ (unsigned long) buffere->addr);
+
/*
* A single used SBALE per inbound SBALE has been
* implemented by QDIO so far. Hope they will
return;
}
-/*
- * function: zfcp_qdio_reqid_check
- *
- * purpose: checks for valid reqids or unsolicited status
- *
- * returns: 0 - valid request id or unsolicited status
- * !0 - otherwise
- */
-int
-zfcp_qdio_reqid_check(struct zfcp_adapter *adapter, void *sbale_addr)
-{
- struct zfcp_fsf_req *fsf_req;
- unsigned long flags;
-
- /* invalid (per convention used in this driver) */
- if (unlikely(!sbale_addr)) {
- ZFCP_LOG_NORMAL("bug: invalid reqid\n");
- return -EINVAL;
- }
-
- /* valid request id and thus (hopefully :) valid fsf_req address */
- fsf_req = (struct zfcp_fsf_req *) sbale_addr;
-
- /* serialize with zfcp_fsf_req_dismiss_all */
- spin_lock_irqsave(&adapter->fsf_req_list_lock, flags);
- if (list_empty(&adapter->fsf_req_list_head)) {
- spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
- return 0;
- }
- list_del(&fsf_req->list);
- atomic_dec(&adapter->fsf_reqs_active);
- spin_unlock_irqrestore(&adapter->fsf_req_list_lock, flags);
-
- if (unlikely(adapter != fsf_req->adapter)) {
- ZFCP_LOG_NORMAL("bug: invalid reqid (fsf_req=%p, "
- "fsf_req->adapter=%p, adapter=%p)\n",
- fsf_req, fsf_req->adapter, adapter);
- return -EINVAL;
- }
-
- /* finish the FSF request */
- zfcp_fsf_req_complete(fsf_req);
-
- return 0;
-}
-
/**
* zfcp_qdio_sbale_get - return pointer to SBALE of qdio_queue
* @queue: queue from which SBALE should be returned
* zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for
* a struct zfcp_fsf_req
*/
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
{
return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue,
* zfcp_qdio_sbale_curr - return current SBALE on request_queue for
* a struct zfcp_fsf_req
*/
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
{
return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr,
*
* Note: We can assume at least one free SBAL in the request_queue when called.
*/
-static inline void
+static void
zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
{
int count = atomic_read(&fsf_req->adapter->request_queue.free_count);
*
* This function changes sbal_curr, sbale_curr, sbal_number of fsf_req.
*/
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
volatile struct qdio_buffer_element *sbale;
/**
* zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed
*/
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
{
if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
* zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue
* with zero from
*/
-static inline int
+static int
zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last)
{
struct qdio_buffer **buf = queue->buffer;
* zfcp_qdio_sbale_fill - set address and lenght in current SBALE
* on request_queue
*/
-static inline void
+static void
zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *addr, int length)
{
* Alignment and length of the segment determine how many SBALEs are needed
* for the memory segment.
*/
-static inline int
+static int
zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *start_addr, unsigned long total_length)
{
* @sg_count: number of elements in scatter-gather list
* @max_sbals: upper bound for number of SBALs to be used
*/
-inline int
+int
zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
struct scatterlist *sg, int sg_count, int max_sbals)
{
* @length: length of buffer
* @max_sbals: upper bound for number of SBALs to be used
*/
-static inline int
+static int
zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
void *buffer, unsigned long length, int max_sbals)
{
* @scsi_cmnd: either scatter-gather list or buffer contained herein is used
* to fill SBALs
*/
-inline int
+int
zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
{