drivers/scsi/libsas/sas_expander.c

Source file repositories/reference/linux-study-clean/drivers/scsi/libsas/sas_expander.c

File Facts

System
Linux kernel
Corpus path
drivers/scsi/libsas/sas_expander.c
Extension
.c
Size
55619 bytes
Lines
2176
Domain
Driver Families
Bucket
drivers/scsi
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 (test_bit(SAS_DEV_GONE, &dev->state)) {
			res = -ECOMM;
			break;
		}

		task = sas_alloc_slow_task(GFP_KERNEL);
		if (!task) {
			res = -ENOMEM;
			break;
		}
		task->dev = dev;
		task->task_proto = dev->tproto;
		task->smp_task.smp_req = *req;
		task->smp_task.smp_resp = *resp;

		task->task_done = sas_task_internal_done;

		task->slow_task->timer.function = sas_task_internal_timedout;
		task->slow_task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
		add_timer(&task->slow_task->timer);

		res = i->dft->lldd_execute_task(task, GFP_KERNEL);

		if (res) {
			timer_delete_sync(&task->slow_task->timer);
			pr_notice("executing SMP task failed:%d\n", res);
			break;
		}

		wait_for_completion(&task->slow_task->completion);
		res = -ECOMM;
		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
			pr_notice("smp task timed out or aborted\n");
			i->dft->lldd_abort_task(task);
			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
				pr_notice("SMP task aborted and not done\n");
				break;
			}
		}
		if (task->task_status.resp == SAS_TASK_COMPLETE &&
		    task->task_status.stat == SAS_SAM_STAT_GOOD) {
			res = 0;
			break;
		}
		if (task->task_status.resp == SAS_TASK_COMPLETE &&
		    task->task_status.stat == SAS_DATA_UNDERRUN) {
			/* no error, but return the number of bytes of
			 * underrun */
			res = task->task_status.residual;
			break;
		}
		if (task->task_status.resp == SAS_TASK_COMPLETE &&
		    task->task_status.stat == SAS_DATA_OVERRUN) {
			res = -EMSGSIZE;
			break;
		}
		if (task->task_status.resp == SAS_TASK_UNDELIVERED &&
		    task->task_status.stat == SAS_DEVICE_UNKNOWN)
			break;
		else {
			pr_notice("%s: task to dev %016llx response: 0x%x status 0x%x\n",
				  __func__,
				  SAS_ADDR(dev->sas_addr),
				  task->task_status.resp,
				  task->task_status.stat);
			sas_free_task(task);
			task = NULL;
		}
	}
	mutex_unlock(&dev->ex_dev.cmd_mutex);
	pm_runtime_put_sync(ha->dev);

	BUG_ON(retry == 3 && task != NULL);
	sas_free_task(task);
	return res;
}

static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
			    void *resp, int resp_size)
{
	struct scatterlist req_sg;
	struct scatterlist resp_sg;

	sg_init_one(&req_sg, req, req_size);
	sg_init_one(&resp_sg, resp, resp_size);
	return smp_execute_task_sg(dev, &req_sg, &resp_sg);
}

/* ---------- Allocations ---------- */

Annotation

Implementation Notes