Index: sbin/camcontrol/camcontrol.8 =================================================================== --- sbin/camcontrol/camcontrol.8 +++ sbin/camcontrol/camcontrol.8 @@ -27,7 +27,7 @@ .\" .\" $FreeBSD$ .\" -.Dd August 6, 2015 +.Dd April 26, 2016 .Dt CAMCONTROL 8 .Os .Sh NAME @@ -98,6 +98,9 @@ .Op device id .Op generic args .Nm +.Ic reprobe +.Op device id +.Nm .Ic rescan .Aq all | bus Ns Op :target:lun .Nm @@ -518,6 +521,12 @@ Print out the last logical block or the size of the device only, and omit the blocksize. .El +.Pp +Note that this command only displays the information, it does not update +the kernel data structures. +Use the +.Nm +reprobe subcommand to do that. .It Ic start Send the SCSI Start/Stop Unit (0x1B) command to the given device with the start bit set. @@ -539,6 +548,12 @@ may specify a scan of all busses, a single bus, or a lun. Scanning all luns on a target is not supported. +.It Ic reprobe +Tell the kernel to refresh the information about the device and +notify the upper layer, +.Xr GEOM 4 . +This includes sending the SCSI READ CAPACITY command and updating +the disk size visible to the rest of the system. .It Ic reset Tell the kernel to reset all busses in the system (with the .Ar all Index: sbin/camcontrol/camcontrol.c =================================================================== --- sbin/camcontrol/camcontrol.c +++ sbin/camcontrol/camcontrol.c @@ -100,7 +100,8 @@ CAM_CMD_APM = 0x00000021, CAM_CMD_AAM = 0x00000022, CAM_CMD_ATTRIB = 0x00000023, - CAM_CMD_OPCODES = 0x00000024 + CAM_CMD_OPCODES = 0x00000024, + CAM_CMD_REPROBE = 0x00000025 } cam_cmdmask; typedef enum { @@ -190,6 +191,7 @@ {"eject", CAM_CMD_STARTSTOP, CAM_ARG_EJECT, NULL}, {"reportluns", CAM_CMD_REPORTLUNS, CAM_ARG_NONE, "clr:"}, {"readcapacity", CAM_CMD_READCAP, CAM_ARG_NONE, "bhHNqs"}, + {"reprobe", CAM_CMD_REPROBE, CAM_ARG_NONE, NULL}, #endif /* MINIMALISTIC */ {"rescan", CAM_CMD_RESCAN, CAM_ARG_NONE, NULL}, {"reset", CAM_CMD_RESET, CAM_ARG_NONE, NULL}, @@ -328,6 +330,7 @@ static int scsiopcodes(struct cam_device *device, int argc, char **argv, char *combinedopt, int retry_count, int timeout, int verbose); +static int scsireprobe(struct cam_device *device); #endif /* MINIMALISTIC */ #ifndef min @@ -8663,6 +8666,42 @@ #endif /* MINIMALISTIC */ +static int +scsireprobe(struct cam_device *device) +{ + union ccb *ccb; + int retval = 0; + + ccb = cam_getccb(device); + + if (ccb == NULL) { + warnx("%s: error allocating ccb", __func__); + return (1); + } + + bzero(&(&ccb->ccb_h)[1], + sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); + + ccb->ccb_h.func_code = XPT_REPROBE_LUN; + + if (cam_send_ccb(device, ccb) < 0) { + warn("error sending XPT_REPROBE_LUN CCB"); + retval = 1; + goto bailout; + } + + if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { + cam_error_print(device, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); + retval = 1; + goto bailout; + } + +bailout: + cam_freeccb(ccb); + + return (retval); +} + void usage(int printlong) { @@ -8682,6 +8721,7 @@ " camcontrol stop [dev_id][generic args]\n" " camcontrol load [dev_id][generic args]\n" " camcontrol eject [dev_id][generic args]\n" +" camcontrol reprobe [dev_id][generic args]\n" #endif /* MINIMALISTIC */ " camcontrol rescan \n" " camcontrol reset \n" @@ -8754,6 +8794,7 @@ "stop send a Stop Unit command to the device\n" "load send a Start Unit command to the device with the load bit set\n" "eject send a Stop Unit command to the device with the eject bit set\n" +"reprobe update capacity information of the given device\n" "rescan rescan all busses, the given bus, or bus:target:lun\n" "reset reset all busses, the given bus, or bus:target:lun\n" "defects read the defect list of the specified device\n" @@ -9299,6 +9340,10 @@ error = scsiopcodes(cam_dev, argc, argv, combinedopt, retry_count, timeout, arglist & CAM_ARG_VERBOSE); break; + case CAM_CMD_REPROBE: + error = scsireprobe(cam_dev); + break; + #endif /* MINIMALISTIC */ case CAM_CMD_USAGE: usage(1); Index: sys/cam/cam_ccb.h =================================================================== --- sys/cam/cam_ccb.h +++ sys/cam/cam_ccb.h @@ -231,6 +231,8 @@ /* Notify Host Target driver of event */ XPT_NOTIFY_ACKNOWLEDGE = 0x37 | XPT_FC_QUEUED | XPT_FC_USER_CCB, /* Acknowledgement of event */ + XPT_REPROBE_LUN = 0x38 | XPT_FC_QUEUED | XPT_FC_USER_CCB, + /* Query device capacity and notify GEOM */ /* Vendor Unique codes: 0x80->0x8F */ XPT_VUNIQUE = 0x80 @@ -778,6 +780,7 @@ * Definitions for the asynchronous callback CCB fields. */ typedef enum { + AC_REPROBE = 0x8000,/* Capacity data might have changed */ AC_UNIT_ATTENTION = 0x4000,/* Device reported UNIT ATTENTION */ AC_ADVINFO_CHANGED = 0x2000,/* Advance info might have changes */ AC_CONTRACT = 0x1000,/* A contractual callback */ Index: sys/cam/cam_xpt.c =================================================================== --- sys/cam/cam_xpt.c +++ sys/cam/cam_xpt.c @@ -2994,6 +2994,11 @@ xpt_freeze_devq(path, 1); start_ccb->ccb_h.status = CAM_REQ_CMP; break; + case XPT_REPROBE_LUN: + xpt_async(AC_REPROBE, path, NULL); + start_ccb->ccb_h.status = CAM_REQ_CMP; + xpt_done(start_ccb); + break; default: case XPT_SDEV_TYPE: case XPT_TERM_IO: Index: sys/cam/scsi/scsi_da.c =================================================================== --- sys/cam/scsi/scsi_da.c +++ sys/cam/scsi/scsi_da.c @@ -1769,6 +1769,11 @@ ccbh->ccb_state |= DA_CCB_RETRY_UA; break; } + case AC_REPROBE: + softc = (struct da_softc *)periph->softc; + softc->flags &= ~DA_FLAG_PROBED; + dareprobe(periph); + break; default: break; } @@ -2329,7 +2334,7 @@ * would be to not attach the device on failure. */ xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | - AC_ADVINFO_CHANGED | AC_SCSI_AEN | AC_UNIT_ATTENTION, + AC_ADVINFO_CHANGED | AC_SCSI_AEN | AC_UNIT_ATTENTION | AC_REPROBE, daasync, periph, periph->path); /*