drivers/s390/scsi/zfcp_qdio.c

Source file repositories/reference/linux-study-clean/drivers/s390/scsi/zfcp_qdio.c

File Facts

System
Linux kernel
Corpus path
drivers/s390/scsi/zfcp_qdio.c
Extension
.c
Size
16635 bytes
Lines
598
Domain
Driver Families
Bucket
drivers/s390
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (error) {
			zfcp_qdio_handler_error(qdio, "qdreqt1", error);
		} else {
			/* cleanup all SBALs being program-owned now */
			zfcp_qdio_zero_sbals(qdio->req_q, start, completed);

			spin_lock_irq(&qdio->stat_lock);
			zfcp_qdio_account(qdio);
			spin_unlock_irq(&qdio->stat_lock);
			atomic_add(completed, &qdio->req_q_free);
			wake_up(&qdio->req_q_wq);
		}
	}

	if (atomic_read(&qdio->req_q_free) < QDIO_MAX_BUFFERS_PER_Q)
		timer_reduce(&qdio->request_timer,
			     jiffies + msecs_to_jiffies(ZFCP_QDIO_REQUEST_RESCAN_MSECS));
}

static void zfcp_qdio_request_timer(struct timer_list *timer)
{
	struct zfcp_qdio *qdio = timer_container_of(qdio, timer,
						    request_timer);

	tasklet_schedule(&qdio->request_tasklet);
}

static void zfcp_qdio_int_resp(struct ccw_device *cdev, unsigned int qdio_err,
			       int queue_no, int idx, int count,
			       unsigned long parm)
{
	struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm;
	struct zfcp_adapter *adapter = qdio->adapter;
	int sbal_no, sbal_idx;

	if (unlikely(qdio_err)) {
		if (zfcp_adapter_multi_buffer_active(adapter)) {
			void *pl[ZFCP_QDIO_MAX_SBALS_PER_REQ + 1];
			struct qdio_buffer_element *sbale;
			u64 req_id;
			u8 scount;

			memset(pl, 0,
			       ZFCP_QDIO_MAX_SBALS_PER_REQ * sizeof(void *));
			sbale = qdio->res_q[idx]->element;
			req_id = dma64_to_u64(sbale->addr);
			scount = min(sbale->scount + 1,
				     ZFCP_QDIO_MAX_SBALS_PER_REQ + 1);
				     /* incl. signaling SBAL */

			for (sbal_no = 0; sbal_no < scount; sbal_no++) {
				sbal_idx = (idx + sbal_no) %
					QDIO_MAX_BUFFERS_PER_Q;
				pl[sbal_no] = qdio->res_q[sbal_idx];
			}
			zfcp_dbf_hba_def_err(adapter, req_id, scount, pl);
		}
		zfcp_qdio_handler_error(qdio, "qdires1", qdio_err);
		return;
	}

	/*
	 * go through all SBALs from input queue currently
	 * returned by QDIO layer
	 */
	for (sbal_no = 0; sbal_no < count; sbal_no++) {
		sbal_idx = (idx + sbal_no) % QDIO_MAX_BUFFERS_PER_Q;
		/* go through all SBALEs of SBAL */
		zfcp_fsf_reqid_check(qdio, sbal_idx);
	}

	/*
	 * put SBALs back to response queue
	 */
	if (qdio_add_bufs_to_input_queue(cdev, 0, idx, count))
		zfcp_erp_adapter_reopen(qdio->adapter, 0, "qdires2");
}

static void zfcp_qdio_irq_tasklet(struct tasklet_struct *tasklet)
{
	struct zfcp_qdio *qdio = from_tasklet(qdio, tasklet, irq_tasklet);
	struct ccw_device *cdev = qdio->adapter->ccw_device;
	unsigned int start, error;
	int completed;

	if (atomic_read(&qdio->req_q_free) < QDIO_MAX_BUFFERS_PER_Q)
		tasklet_schedule(&qdio->request_tasklet);

	/* Check the Response Queue: */
	completed = qdio_inspect_input_queue(cdev, 0, &start, &error);

Annotation

Implementation Notes