FreeBSD/sys/cam/ata/ata_xpt.c
/*
 * To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
 * As the scan progresses, xpt_scan_bus is used as the
 * callback on completion function.
 */
To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
As the scan progresses, xpt_scan_bus is used as the
callback on completion function.
To start a scan request_ccb is an XPT_SCAN_BUS ccb . As the scan progresses xpt_scan_bus is used as the callback on completion function .
static void
ata_scan_bus(struct cam_periph *periph, union ccb *request_ccb)
{
	struct	cam_path *path;
	ata_scan_bus_info *scan_info;
	union	ccb *work_ccb, *reset_ccb;
	struct mtx *mtx;
	cam_status status;
	CAM_DEBUG(request_ccb->ccb_h.path, CAM_DEBUG_TRACE,
		  ("xpt_scan_bus\n"));
	switch (request_ccb->ccb_h.func_code) {
	case XPT_SCAN_BUS:
	case XPT_SCAN_TGT:
		work_ccb = xpt_alloc_ccb_nowait();
		if (work_ccb == NULL) {
			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
			xpt_done(request_ccb);
			return;
		}
		xpt_setup_ccb(&work_ccb->ccb_h, request_ccb->ccb_h.path,
			      request_ccb->ccb_h.pinfo.priority);
		work_ccb->ccb_h.func_code = XPT_PATH_INQ;
		xpt_action(work_ccb);
		if (work_ccb->ccb_h.status != CAM_REQ_CMP) {
			request_ccb->ccb_h.status = work_ccb->ccb_h.status;
			xpt_free_ccb(work_ccb);
			xpt_done(request_ccb);
			return;
		}
		if ((work_ccb->cpi.hba_inquiry &
		    (PI_WIDE_32|PI_WIDE_16|PI_SDTR_ABLE)) &&
		    !(work_ccb->cpi.hba_misc & PIM_NOBUSRESET) &&
		    !timevalisset(&request_ccb->ccb_h.path->bus->last_reset)) {
			reset_ccb = xpt_alloc_ccb_nowait();
			if (reset_ccb == NULL) {
				request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
				xpt_free_ccb(work_ccb);
				xpt_done(request_ccb);
				return;
			}
			xpt_setup_ccb(&reset_ccb->ccb_h, request_ccb->ccb_h.path,
			      CAM_PRIORITY_NONE);
			reset_ccb->ccb_h.func_code = XPT_RESET_BUS;
			xpt_action(reset_ccb);
			if (reset_ccb->ccb_h.status != CAM_REQ_CMP) {
				request_ccb->ccb_h.status = reset_ccb->ccb_h.status;
				xpt_free_ccb(reset_ccb);
				xpt_free_ccb(work_ccb);
				xpt_done(request_ccb);
				return;
			}
			xpt_free_ccb(reset_ccb);
		}
		scan_info = (ata_scan_bus_info *)
		    malloc(sizeof(ata_scan_bus_info), M_CAMXPT, M_NOWAIT);
		if (scan_info == NULL) {
			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
			xpt_free_ccb(work_ccb);
			xpt_done(request_ccb);
			return;
		}
		scan_info->request_ccb = request_ccb;
		scan_info->cpi = &work_ccb->cpi;
		if (scan_info->cpi->hba_inquiry & PI_SATAPM)
			scan_info->counter = scan_info->cpi->max_target;
		else
			scan_info->counter = 0;
		work_ccb = xpt_alloc_ccb_nowait();
		if (work_ccb == NULL) {
			free(scan_info, M_CAMXPT);
			request_ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
			xpt_done(request_ccb);
			break;
		}
		mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
		goto scan_next;
	case XPT_SCAN_LUN:
		work_ccb = request_ccb;
		scan_info = (ata_scan_bus_info *)work_ccb->ccb_h.ppriv_ptr0;
		mtx = xpt_path_mtx(scan_info->request_ccb->ccb_h.path);
		mtx_lock(mtx);
		if ((scan_info->cpi->hba_inquiry & PI_SATAPM) &&
		    (scan_info->counter == scan_info->cpi->max_target)) {
			if (work_ccb->ccb_h.status == CAM_REQ_CMP) {
				xpt_free_path(work_ccb->ccb_h.path);
				goto done;
			} else {
				struct ccb_trans_settings cts;
				bzero(&cts, sizeof(cts));
				xpt_setup_ccb(&cts.ccb_h,
				    work_ccb->ccb_h.path, CAM_PRIORITY_NONE);
				cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS;
				cts.type = CTS_TYPE_CURRENT_SETTINGS;
				cts.xport_specific.sata.pm_present = 0;
				cts.xport_specific.sata.valid = CTS_SATA_VALID_PM;
				xpt_action((union ccb *)&cts);
			}
		}
		xpt_free_path(work_ccb->ccb_h.path);
		if (scan_info->counter ==
		    ((scan_info->cpi->hba_inquiry & PI_SATAPM) ?
		    0 : scan_info->cpi->max_target)) {
done:
			mtx_unlock(mtx);
			xpt_free_ccb(work_ccb);
			xpt_free_ccb((union ccb *)scan_info->cpi);
			request_ccb = scan_info->request_ccb;
			free(scan_info, M_CAMXPT);
			request_ccb->ccb_h.status = CAM_REQ_CMP;
			xpt_done(request_ccb);
			break;
		}
		scan_info->counter = (scan_info->counter + 1 ) %
		    (scan_info->cpi->max_target + 1);
scan_next:
		status = xpt_create_path(&path, NULL,
		    scan_info->request_ccb->ccb_h.path_id,
		    scan_info->counter, 0);
		if (status != CAM_REQ_CMP) {
			if (request_ccb->ccb_h.func_code == XPT_SCAN_LUN)
				mtx_unlock(mtx);
			printf("xpt_scan_bus: xpt_create_path failed"
			    " with status %#x, bus scan halted\n",
			    status);
			xpt_free_ccb(work_ccb);
			xpt_free_ccb((union ccb *)scan_info->cpi);
			request_ccb = scan_info->request_ccb;
			free(scan_info, M_CAMXPT);
			request_ccb->ccb_h.status = status;
			xpt_done(request_ccb);
			break;
		}
		xpt_setup_ccb(&work_ccb->ccb_h, path,
		    scan_info->request_ccb->ccb_h.pinfo.priority);
		work_ccb->ccb_h.func_code = XPT_SCAN_LUN;
		work_ccb->ccb_h.cbfcnp = ata_scan_bus;
		work_ccb->ccb_h.flags |= CAM_UNLOCKED;
		work_ccb->ccb_h.ppriv_ptr0 = scan_info;
		work_ccb->crcn.flags = scan_info->request_ccb->crcn.flags;
		mtx_unlock(mtx);
		if (request_ccb->ccb_h.func_code == XPT_SCAN_LUN)
			mtx = NULL;
		xpt_action(work_ccb);
		if (mtx != NULL)
			mtx_lock(mtx);
		break;
	default:
		break;
	}
}
static void ata_scan_bus ( struct cam_periph * periph , union ccb * request_ccb ) { struct cam_path * path ; ata_scan_bus_info * scan_info ; union ccb * work_ccb , * reset_ccb ; struct mtx * mtx ; cam_status status ; CAM_DEBUG ( request_ccb -> ccb_h . path , CAM_DEBUG_TRACE , ( " \n " ) ) ; switch ( request_ccb -> ccb_h . func_code ) { case XPT_SCAN_BUS : case XPT_SCAN_TGT : work_ccb = xpt_alloc_ccb_nowait ( ) ; if ( work_ccb == NULL ) { request_ccb -> ccb_h . status = CAM_RESRC_UNAVAIL ; xpt_done ( request_ccb ) ; return ; } xpt_setup_ccb ( & work_ccb -> ccb_h , request_ccb -> ccb_h . path , request_ccb -> ccb_h . pinfo . priority ) ; work_ccb -> ccb_h . func_code = XPT_PATH_INQ ; xpt_action ( work_ccb ) ; if ( work_ccb -> ccb_h . status != CAM_REQ_CMP ) { request_ccb -> ccb_h . status = work_ccb -> ccb_h . status ; xpt_free_ccb ( work_ccb ) ; xpt_done ( request_ccb ) ; return ; } if ( ( work_ccb -> cpi . hba_inquiry & ( PI_WIDE_32 | PI_WIDE_16 | PI_SDTR_ABLE ) ) && ! ( work_ccb -> cpi . hba_misc & PIM_NOBUSRESET ) && ! timevalisset ( & request_ccb -> ccb_h . path -> bus -> last_reset ) ) { reset_ccb = xpt_alloc_ccb_nowait ( ) ; if ( reset_ccb == NULL ) { request_ccb -> ccb_h . status = CAM_RESRC_UNAVAIL ; xpt_free_ccb ( work_ccb ) ; xpt_done ( request_ccb ) ; return ; } xpt_setup_ccb ( & reset_ccb -> ccb_h , request_ccb -> ccb_h . path , CAM_PRIORITY_NONE ) ; reset_ccb -> ccb_h . func_code = XPT_RESET_BUS ; xpt_action ( reset_ccb ) ; if ( reset_ccb -> ccb_h . status != CAM_REQ_CMP ) { request_ccb -> ccb_h . status = reset_ccb -> ccb_h . status ; xpt_free_ccb ( reset_ccb ) ; xpt_free_ccb ( work_ccb ) ; xpt_done ( request_ccb ) ; return ; } xpt_free_ccb ( reset_ccb ) ; } scan_info = ( ata_scan_bus_info * ) malloc ( sizeof ( ata_scan_bus_info ) , M_CAMXPT , M_NOWAIT ) ; if ( scan_info == NULL ) { request_ccb -> ccb_h . status = CAM_RESRC_UNAVAIL ; xpt_free_ccb ( work_ccb ) ; xpt_done ( request_ccb ) ; return ; } scan_info -> request_ccb = request_ccb ; scan_info -> cpi = & work_ccb -> cpi ; if ( scan_info -> cpi -> hba_inquiry & PI_SATAPM ) scan_info -> counter = scan_info -> cpi -> max_target ; else scan_info -> counter = 0 ; work_ccb = xpt_alloc_ccb_nowait ( ) ; if ( work_ccb == NULL ) { free ( scan_info , M_CAMXPT ) ; request_ccb -> ccb_h . status = CAM_RESRC_UNAVAIL ; xpt_done ( request_ccb ) ; break ; } mtx = xpt_path_mtx ( scan_info -> request_ccb -> ccb_h . path ) ; goto scan_next ; case XPT_SCAN_LUN : work_ccb = request_ccb ; scan_info = ( ata_scan_bus_info * ) work_ccb -> ccb_h . ppriv_ptr0 ; mtx = xpt_path_mtx ( scan_info -> request_ccb -> ccb_h . path ) ; mtx_lock ( mtx ) ; if ( ( scan_info -> cpi -> hba_inquiry & PI_SATAPM ) && ( scan_info -> counter == scan_info -> cpi -> max_target ) ) { if ( work_ccb -> ccb_h . status == CAM_REQ_CMP ) { xpt_free_path ( work_ccb -> ccb_h . path ) ; goto done ; } else { struct ccb_trans_settings cts ; bzero ( & cts , sizeof ( cts ) ) ; xpt_setup_ccb ( & cts . ccb_h , work_ccb -> ccb_h . path , CAM_PRIORITY_NONE ) ; cts . ccb_h . func_code = XPT_SET_TRAN_SETTINGS ; cts . type = CTS_TYPE_CURRENT_SETTINGS ; cts . xport_specific . sata . pm_present = 0 ; cts . xport_specific . sata . valid = CTS_SATA_VALID_PM ; xpt_action ( ( union ccb * ) & cts ) ; } } xpt_free_path ( work_ccb -> ccb_h . path ) ; if ( scan_info -> counter == ( ( scan_info -> cpi -> hba_inquiry & PI_SATAPM ) ? 0 : scan_info -> cpi -> max_target ) ) { done : mtx_unlock ( mtx ) ; xpt_free_ccb ( work_ccb ) ; xpt_free_ccb ( ( union ccb * ) scan_info -> cpi ) ; request_ccb = scan_info -> request_ccb ; free ( scan_info , M_CAMXPT ) ; request_ccb -> ccb_h . status = CAM_REQ_CMP ; xpt_done ( request_ccb ) ; break ; } scan_info -> counter = ( scan_info -> counter + 1 ) % ( scan_info -> cpi -> max_target + 1 ) ; scan_next : status = xpt_create_path ( & path , NULL , scan_info -> request_ccb -> ccb_h . path_id , scan_info -> counter , 0 ) ; if ( status != CAM_REQ_CMP ) { if ( request_ccb -> ccb_h . func_code == XPT_SCAN_LUN ) mtx_unlock ( mtx ) ; printf ( " " " \n " , status ) ; xpt_free_ccb ( work_ccb ) ; xpt_free_ccb ( ( union ccb * ) scan_info -> cpi ) ; request_ccb = scan_info -> request_ccb ; free ( scan_info , M_CAMXPT ) ; request_ccb -> ccb_h . status = status ; xpt_done ( request_ccb ) ; break ; } xpt_setup_ccb ( & work_ccb -> ccb_h , path , scan_info -> request_ccb -> ccb_h . pinfo . priority ) ; work_ccb -> ccb_h . func_code = XPT_SCAN_LUN ; work_ccb -> ccb_h . cbfcnp = ata_scan_bus ; work_ccb -> ccb_h . flags |= CAM_UNLOCKED ; work_ccb -> ccb_h . ppriv_ptr0 = scan_info ; work_ccb -> crcn . flags = scan_info -> request_ccb -> crcn . flags ; mtx_unlock ( mtx ) ; if ( request_ccb -> ccb_h . func_code == XPT_SCAN_LUN ) mtx = NULL ; xpt_action ( work_ccb ) ; if ( mtx != NULL ) mtx_lock ( mtx ) ; break ; default : break ; } }
To start a scan, request_ccb is an XPT_SCAN_BUS ccb.
To start a scan request_ccb is an XPT_SCAN_BUS ccb .
/* Find out the characteristics of the bus */ /* We may need to reset bus first, if we haven't done it yet. */ /* Save some state for use while we probe for devices */ /* If PM supported, probe it first. */ /* Reuse the same CCB to query if a device was really found */ /* If there is PMP... */ /* everything else will be probed by it */ /* Free the current request path- we're done with it. */ /* Report SIM that PM is absent. */ /* Free the current request path- we're done with it. */ /* Take next device. Wrap from max (PMP) to 0. */