aboutsummaryrefslogtreecommitdiff
path: root/sys/cam
diff options
context:
space:
mode:
authorJustin T. Gibbs <gibbs@FreeBSD.org>2011-06-14 17:10:32 +0000
committerJustin T. Gibbs <gibbs@FreeBSD.org>2011-06-14 17:10:32 +0000
commit416494d7c915a8d33f4f3e10ed61b9b079d03076 (patch)
tree2ba93494158658cf752e99e3930ef38a4872311c /sys/cam
parentf528c3fdbc7a5a86413363b8a703a5f74c407953 (diff)
downloadsrc-416494d7c915a8d33f4f3e10ed61b9b079d03076.tar.gz
src-416494d7c915a8d33f4f3e10ed61b9b079d03076.zip
Notes
Diffstat (limited to 'sys/cam')
-rw-r--r--sys/cam/ata/ata_da.c22
-rw-r--r--sys/cam/scsi/scsi_da.c67
-rw-r--r--sys/cam/scsi/scsi_pass.c75
3 files changed, 140 insertions, 24 deletions
diff --git a/sys/cam/ata/ata_da.c b/sys/cam/ata/ata_da.c
index 8e933022390f..f1a943376752 100644
--- a/sys/cam/ata/ata_da.c
+++ b/sys/cam/ata/ata_da.c
@@ -812,6 +812,25 @@ adasysctlinit(void *context, int pending)
cam_periph_release(periph);
}
+static int
+adagetattr(struct bio *bp)
+{
+ int ret = -1;
+ struct cam_periph *periph;
+
+ if (bp->bio_disk == NULL || bp->bio_disk->d_drv1)
+ return ENXIO;
+ periph = (struct cam_periph *)bp->bio_disk->d_drv1;
+ if (periph->path == NULL)
+ return ENXIO;
+
+ ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute,
+ periph->path);
+ if (ret == 0)
+ bp->bio_completed = bp->bio_length;
+ return ret;
+}
+
static cam_status
adaregister(struct cam_periph *periph, void *arg)
{
@@ -917,6 +936,7 @@ adaregister(struct cam_periph *periph, void *arg)
softc->disk->d_open = adaopen;
softc->disk->d_close = adaclose;
softc->disk->d_strategy = adastrategy;
+ softc->disk->d_getattr = adagetattr;
softc->disk->d_dump = adadump;
softc->disk->d_name = "ada";
softc->disk->d_drv1 = periph;
@@ -938,8 +958,6 @@ adaregister(struct cam_periph *periph, void *arg)
((softc->flags & ADA_FLAG_CAN_CFA) &&
!(softc->flags & ADA_FLAG_CAN_48BIT)))
softc->disk->d_flags |= DISKFLAG_CANDELETE;
- strlcpy(softc->disk->d_ident, cgd->serial_num,
- MIN(sizeof(softc->disk->d_ident), cgd->serial_num_len + 1));
strlcpy(softc->disk->d_descr, cgd->ident_data.model,
MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model)));
softc->disk->d_hba_vendor = cpi.hba_vendor;
diff --git a/sys/cam/scsi/scsi_da.c b/sys/cam/scsi/scsi_da.c
index b6f7cf5960ce..a4363186a0b8 100644
--- a/sys/cam/scsi/scsi_da.c
+++ b/sys/cam/scsi/scsi_da.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <sys/eventhandler.h>
#include <sys/malloc.h>
#include <sys/cons.h>
+#include <geom/geom.h>
#include <geom/geom_disk.h>
#endif /* _KERNEL */
@@ -933,6 +934,25 @@ dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t leng
return (0);
}
+static int
+dagetattr(struct bio *bp)
+{
+ int ret = -1;
+ struct cam_periph *periph;
+
+ if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL)
+ return ENXIO;
+ periph = (struct cam_periph *)bp->bio_disk->d_drv1;
+ if (periph->path == NULL)
+ return ENXIO;
+
+ ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute,
+ periph->path);
+ if (ret == 0)
+ bp->bio_completed = bp->bio_length;
+ return ret;
+}
+
static void
dainit(void)
{
@@ -1046,6 +1066,20 @@ daasync(void *callback_arg, u_int32_t code,
&& status != CAM_REQ_INPROG)
printf("daasync: Unable to attach to new device "
"due to status 0x%x\n", status);
+ return;
+ }
+ case AC_ADVINFO_CHANGED:
+ {
+ uintptr_t buftype;
+
+ buftype = (uintptr_t)arg;
+ if (buftype == CDAI_TYPE_PHYS_PATH) {
+ struct da_softc *softc;
+
+ softc = periph->softc;
+ disk_attr_changed(softc->disk, "GEOM::physpath",
+ M_NOWAIT);
+ }
break;
}
case AC_SENT_BDR:
@@ -1233,17 +1267,6 @@ daregister(struct cam_periph *periph, void *arg)
TASK_INIT(&softc->sysctl_task, 0, dasysctlinit, periph);
/*
- * Add async callbacks for bus reset and
- * bus device reset calls. I don't bother
- * checking if this fails as, in most cases,
- * the system will function just fine without
- * them and the only alternative would be to
- * not attach the device on failure.
- */
- xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
- daasync, periph, periph->path);
-
- /*
* Take an exclusive refcount on the periph while dastart is called
* to finish the probe. The reference will be dropped in dadone at
* the end of probe.
@@ -1303,6 +1326,7 @@ daregister(struct cam_periph *periph, void *arg)
softc->disk->d_close = daclose;
softc->disk->d_strategy = dastrategy;
softc->disk->d_dump = dadump;
+ softc->disk->d_getattr = dagetattr;
softc->disk->d_name = "da";
softc->disk->d_drv1 = periph;
if (cpi.maxio == 0)
@@ -1315,8 +1339,6 @@ daregister(struct cam_periph *periph, void *arg)
softc->disk->d_flags = 0;
if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0)
softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
- strlcpy(softc->disk->d_ident, cgd->serial_num,
- MIN(sizeof(softc->disk->d_ident), cgd->serial_num_len + 1));
cam_strvis(softc->disk->d_descr, cgd->inq_data.vendor,
sizeof(cgd->inq_data.vendor), sizeof(softc->disk->d_descr));
strlcat(softc->disk->d_descr, " ", sizeof(softc->disk->d_descr));
@@ -1330,6 +1352,25 @@ daregister(struct cam_periph *periph, void *arg)
disk_create(softc->disk, DISK_VERSION);
mtx_lock(periph->sim->mtx);
+ /*
+ * Add async callbacks for events of interest.
+ * I don't bother checking if this fails as,
+ * in most cases, the system will function just
+ * fine without them and the only alternative
+ * would be to not attach the device on failure.
+ */
+ xpt_register_async(AC_SENT_BDR | AC_BUS_RESET
+ | AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
+ daasync, periph, periph->path);
+
+ /*
+ * Emit an attribute changed notification just in case
+ * physical path information arrived before our async
+ * event handler was registered, but after anyone attaching
+ * to our disk device polled it.
+ */
+ disk_attr_changed(softc->disk, "GEOM::physpath", M_NOWAIT);
+
xpt_schedule(periph, CAM_PRIORITY_DEV);
return(CAM_REQ_CMP);
diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c
index 5b24d8238c23..a124468a56dc 100644
--- a/sys/cam/scsi/scsi_pass.c
+++ b/sys/cam/scsi/scsi_pass.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/errno.h>
#include <sys/devicestat.h>
#include <sys/proc.h>
+#include <sys/taskqueue.h>
#include <cam/cam.h>
#include <cam/cam_ccb.h>
@@ -70,12 +71,14 @@ typedef enum {
#define ccb_bp ppriv_ptr1
struct pass_softc {
- pass_state state;
- pass_flags flags;
- u_int8_t pd_type;
- union ccb saved_ccb;
- struct devstat *device_stats;
- struct cdev *dev;
+ pass_state state;
+ pass_flags flags;
+ u_int8_t pd_type;
+ union ccb saved_ccb;
+ struct devstat *device_stats;
+ struct cdev *dev;
+ struct cdev *alias_dev;
+ struct task add_physpath_task;
};
@@ -88,6 +91,7 @@ static periph_ctor_t passregister;
static periph_oninv_t passoninvalidate;
static periph_dtor_t passcleanup;
static periph_start_t passstart;
+static void pass_add_physpath(void *context, int pending);
static void passasync(void *callback_arg, u_int32_t code,
struct cam_path *path, void *arg);
static void passdone(struct cam_periph *periph,
@@ -168,17 +172,45 @@ passcleanup(struct cam_periph *periph)
if (bootverbose)
xpt_print(periph->path, "removing device entry\n");
devstat_remove_entry(softc->device_stats);
+
cam_periph_unlock(periph);
+ taskqueue_drain(taskqueue_thread, &softc->add_physpath_task);
+
/*
* passcleanup() is indirectly a d_close method via passclose,
* so using destroy_dev(9) directly can result in deadlock.
*/
destroy_dev_sched(softc->dev);
cam_periph_lock(periph);
+
free(softc, M_DEVBUF);
}
static void
+pass_add_physpath(void *context, int pending)
+{
+ struct cam_periph *periph;
+ struct pass_softc *softc;
+ char *physpath;
+
+ /*
+ * If we have one, create a devfs alias for our
+ * physical path.
+ */
+ periph = context;
+ softc = periph->softc;
+ physpath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK);
+ if (xpt_getattr(physpath, MAXPATHLEN,
+ "GEOM::physpath", periph->path) == 0
+ && strlen(physpath) != 0) {
+
+ make_dev_physpath_alias(MAKEDEV_WAITOK, &softc->alias_dev,
+ softc->dev, softc->alias_dev, physpath);
+ }
+ free(physpath, M_DEVBUF);
+}
+
+static void
passasync(void *callback_arg, u_int32_t code,
struct cam_path *path, void *arg)
{
@@ -219,6 +251,20 @@ passasync(void *callback_arg, u_int32_t code,
break;
}
+ case AC_ADVINFO_CHANGED:
+ {
+ uintptr_t buftype;
+
+ buftype = (uintptr_t)arg;
+ if (buftype == CDAI_TYPE_PHYS_PATH) {
+ struct pass_softc *softc;
+
+ softc = (struct pass_softc *)periph->softc;
+ taskqueue_enqueue(taskqueue_thread,
+ &softc->add_physpath_task);
+ }
+ break;
+ }
default:
cam_periph_async(periph, code, path, arg);
break;
@@ -292,11 +338,22 @@ passregister(struct cam_periph *periph, void *arg)
mtx_lock(periph->sim->mtx);
softc->dev->si_drv1 = periph;
+ TASK_INIT(&softc->add_physpath_task, /*priority*/0,
+ pass_add_physpath, periph);
+
+ /*
+ * See if physical path information is already available.
+ */
+ taskqueue_enqueue(taskqueue_thread, &softc->add_physpath_task);
+
/*
- * Add an async callback so that we get
- * notified if this device goes away.
+ * Add an async callback so that we get notified if
+ * this device goes away or its physical path
+ * (stored in the advanced info data of the EDT) has
+ * changed.
*/
- xpt_register_async(AC_LOST_DEVICE, passasync, periph, periph->path);
+ xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
+ passasync, periph, periph->path);
if (bootverbose)
xpt_announce_periph(periph, NULL);