diff options
Diffstat (limited to 'sys/cam')
-rw-r--r-- | sys/cam/cam_ccb.h | 39 | ||||
-rw-r--r-- | sys/cam/cam_periph.c | 45 | ||||
-rw-r--r-- | sys/cam/cam_periph.h | 8 | ||||
-rw-r--r-- | sys/cam/cam_xpt.c | 129 | ||||
-rw-r--r-- | sys/cam/cam_xpt.h | 2 | ||||
-rw-r--r-- | sys/cam/cam_xpt_internal.h | 2 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_all.c | 203 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_all.h | 67 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_pass.c | 4 | ||||
-rw-r--r-- | sys/cam/scsi/scsi_xpt.c | 80 |
10 files changed, 465 insertions, 114 deletions
diff --git a/sys/cam/cam_ccb.h b/sys/cam/cam_ccb.h index 981a5ed..ed2a890 100644 --- a/sys/cam/cam_ccb.h +++ b/sys/cam/cam_ccb.h @@ -144,8 +144,8 @@ typedef enum { /* Device statistics (error counts, etc.) */ XPT_FREEZE_QUEUE = 0x0d, /* Freeze device queue */ - XPT_GDEV_ADVINFO = 0x0e, - /* Advanced device information */ + XPT_DEV_ADVINFO = 0x0e, + /* Get/Set Device advanced information */ /* SCSI Control Functions: 0x10->0x1F */ XPT_ABORT = 0x10, /* Abort the specified CCB */ @@ -391,15 +391,24 @@ typedef enum { DEV_MATCH_TARGET = 0x002, DEV_MATCH_LUN = 0x004, DEV_MATCH_INQUIRY = 0x008, + DEV_MATCH_DEVID = 0x010, DEV_MATCH_ANY = 0x00f } dev_pattern_flags; +struct device_id_match_pattern { + uint8_t id_len; + uint8_t id[256]; +}; + struct device_match_pattern { - path_id_t path_id; - target_id_t target_id; - lun_id_t target_lun; - struct scsi_static_inquiry_pattern inq_pat; - dev_pattern_flags flags; + path_id_t path_id; + target_id_t target_id; + lun_id_t target_lun; + dev_pattern_flags flags; + union { + struct scsi_static_inquiry_pattern inq_pat; + struct device_id_match_pattern devid_pat; + } data; }; typedef enum { @@ -745,6 +754,7 @@ struct ccb_relsim { * Definitions for the asynchronous callback CCB fields. */ typedef enum { + AC_ADVINFO_CHANGED = 0x2000,/* Advance info might have changes */ AC_CONTRACT = 0x1000,/* A contractual callback */ AC_GETDEV_CHANGED = 0x800,/* Getdev info might have changed */ AC_INQ_CHANGED = 0x400,/* Inquiry info might have changed */ @@ -1094,19 +1104,20 @@ struct ccb_eng_exec { /* This structure must match SCSIIO size */ #define XPT_CCB_INVALID -1 /* for signaling a bad CCB to free */ /* - * CCB for getting advanced device information. This operates in a fashion + * CCB for working with advanced device information. This operates in a fashion * similar to XPT_GDEV_TYPE. Specify the target in ccb_h, the buffer * type requested, and provide a buffer size/buffer to write to. If the - * buffer is too small, the handler will set GDEVAI_FLAG_MORE. + * buffer is too small, provsiz will be larger than bufsiz. */ -struct ccb_getdev_advinfo { +struct ccb_dev_advinfo { struct ccb_hdr ccb_h; uint32_t flags; -#define CGDAI_FLAG_TRANSPORT 0x1 -#define CGDAI_FLAG_PROTO 0x2 +#define CDAI_FLAG_STORE 0x1 /* If set, action becomes store */ uint32_t buftype; /* IN: Type of data being requested */ /* NB: buftype is interpreted on a per-transport basis */ -#define CGDAI_TYPE_SCSI_DEVID 1 +#define CDAI_TYPE_SCSI_DEVID 1 +#define CDAI_TYPE_SERIAL_NUM 2 +#define CDAI_TYPE_PHYS_PATH 3 off_t bufsiz; /* IN: Size of external buffer */ #define CAM_SCSI_DEVID_MAXLEN 65536 /* length in buffer is an uint16_t */ off_t provsiz; /* OUT: Size required/used */ @@ -1151,7 +1162,7 @@ union ccb { struct ccb_rescan crcn; struct ccb_debug cdbg; struct ccb_ataio ataio; - struct ccb_getdev_advinfo cgdai; + struct ccb_dev_advinfo cdai; }; __BEGIN_DECLS diff --git a/sys/cam/cam_periph.c b/sys/cam/cam_periph.c index dd51bca..f630772 100644 --- a/sys/cam/cam_periph.c +++ b/sys/cam/cam_periph.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/proc.h> #include <sys/devicestat.h> #include <sys/bus.h> +#include <sys/sbuf.h> #include <vm/vm.h> #include <vm/vm_extern.h> @@ -303,6 +304,38 @@ cam_periph_find(struct cam_path *path, char *name) return(NULL); } +/* + * Find a peripheral structure with the specified path, target, lun, + * and (optionally) type. If the name is NULL, this function will return + * the first peripheral driver that matches the specified path. + */ +int +cam_periph_list(struct cam_path *path, struct sbuf *sb) +{ + struct periph_driver **p_drv; + struct cam_periph *periph; + int count; + + count = 0; + xpt_lock_buses(); + for (p_drv = periph_drivers; *p_drv != NULL; p_drv++) { + + TAILQ_FOREACH(periph, &(*p_drv)->units, unit_links) { + if (xpt_path_comp(periph->path, path) != 0) + continue; + + if (sbuf_len(sb) != 0) + sbuf_cat(sb, ","); + + sbuf_printf(sb, "%s%d", periph->periph_name, + periph->unit_number); + count++; + } + } + xpt_unlock_buses(); + return (count); +} + cam_status cam_periph_acquire(struct cam_periph *periph) { @@ -654,12 +687,12 @@ cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo) dirs[1] = CAM_DIR_IN; numbufs = 2; break; - case XPT_GDEV_ADVINFO: - if (ccb->cgdai.bufsiz == 0) + case XPT_DEV_ADVINFO: + if (ccb->cdai.bufsiz == 0) return (0); - data_ptrs[0] = (uint8_t **)&ccb->cgdai.buf; - lengths[0] = ccb->cgdai.bufsiz; + data_ptrs[0] = (uint8_t **)&ccb->cdai.buf; + lengths[0] = ccb->cdai.bufsiz; dirs[0] = CAM_DIR_IN; numbufs = 1; @@ -813,9 +846,9 @@ cam_periph_unmapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo) data_ptrs[0] = &ccb->smpio.smp_request; data_ptrs[1] = &ccb->smpio.smp_response; break; - case XPT_GDEV_ADVINFO: + case XPT_DEV_ADVINFO: numbufs = min(mapinfo->num_bufs_used, 1); - data_ptrs[0] = (uint8_t **)&ccb->cgdai.buf; + data_ptrs[0] = (uint8_t **)&ccb->cdai.buf; break; default: /* allow ourselves to be swapped once again */ diff --git a/sys/cam/cam_periph.h b/sys/cam/cam_periph.h index 33e9f75..58bfd7b 100644 --- a/sys/cam/cam_periph.h +++ b/sys/cam/cam_periph.h @@ -142,6 +142,7 @@ cam_status cam_periph_alloc(periph_ctor_t *periph_ctor, char *name, cam_periph_type type, struct cam_path *, ac_callback_t *, ac_code, void *arg); struct cam_periph *cam_periph_find(struct cam_path *path, char *name); +int cam_periph_list(struct cam_path *, struct sbuf *); cam_status cam_periph_acquire(struct cam_periph *periph); void cam_periph_release(struct cam_periph *periph); void cam_periph_release_locked(struct cam_periph *periph); @@ -200,5 +201,12 @@ cam_periph_owned(struct cam_periph *periph) return (mtx_owned(periph->sim->mtx)); } +static __inline int +cam_periph_sleep(struct cam_periph *periph, void *chan, int priority, + const char *wmesg, int timo) +{ + return (msleep(chan, periph->sim->mtx, priority, wmesg, timo)); +} + #endif /* _KERNEL */ #endif /* _CAM_CAM_PERIPH_H */ diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c index 1ce205d..f234076 100644 --- a/sys/cam/cam_xpt.c +++ b/sys/cam/cam_xpt.c @@ -287,9 +287,6 @@ static xpt_targetfunc_t xptdeftargetfunc; static xpt_devicefunc_t xptdefdevicefunc; static xpt_periphfunc_t xptdefperiphfunc; static void xpt_finishconfig_task(void *context, int pending); -static int xpt_for_all_busses(xpt_busfunc_t *tr_func, void *arg); -static int xpt_for_all_devices(xpt_devicefunc_t *tr_func, - void *arg); static void xpt_dev_async_default(u_int32_t async_code, struct cam_eb *bus, struct cam_et *target, @@ -1105,6 +1102,44 @@ xpt_announce_periph(struct cam_periph *periph, char *announce_string) periph->unit_number, announce_string); } +int +xpt_getattr(char *buf, size_t len, const char *attr, struct cam_path *path) +{ + int ret = -1; + struct ccb_dev_advinfo cdai; + + memset(&cdai, 0, sizeof(cdai)); + xpt_setup_ccb(&cdai.ccb_h, path, CAM_PRIORITY_NORMAL); + cdai.ccb_h.func_code = XPT_DEV_ADVINFO; + cdai.bufsiz = len; + + if (!strcmp(attr, "GEOM::ident")) + cdai.buftype = CDAI_TYPE_SERIAL_NUM; + else if (!strcmp(attr, "GEOM::physpath")) + cdai.buftype = CDAI_TYPE_PHYS_PATH; + else + goto out; + + cdai.buf = malloc(cdai.bufsiz, M_CAMXPT, M_NOWAIT|M_ZERO); + if (cdai.buf == NULL) { + ret = ENOMEM; + goto out; + } + xpt_action((union ccb *)&cdai); /* can only be synchronous */ + if ((cdai.ccb_h.status & CAM_DEV_QFRZN) != 0) + cam_release_devq(cdai.ccb_h.path, 0, 0, 0, FALSE); + if (cdai.provsiz == 0) + goto out; + ret = 0; + if (strlcpy(buf, cdai.buf, len) >= len) + ret = EFAULT; + +out: + if (cdai.buf != NULL) + free(cdai.buf, M_CAMXPT); + return ret; +} + static dev_match_ret xptbusmatch(struct dev_match_pattern *patterns, u_int num_patterns, struct cam_eb *bus) @@ -1241,6 +1276,7 @@ xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, for (i = 0; i < num_patterns; i++) { struct device_match_pattern *cur_pattern; + struct scsi_vpd_device_id *device_id_page; /* * If the pattern in question isn't for a device node, we @@ -1255,22 +1291,17 @@ xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, cur_pattern = &patterns[i].pattern.device_pattern; + /* Error out if mutually exclusive options are specified. */ + if ((cur_pattern->flags & (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) + == (DEV_MATCH_INQUIRY|DEV_MATCH_DEVID)) + return(DM_RET_ERROR); + /* * If they want to match any device node, we give them any * device node. */ - if (cur_pattern->flags == DEV_MATCH_ANY) { - /* set the copy flag */ - retval |= DM_RET_COPY; - - - /* - * If we've already decided on an action, go ahead - * and return. - */ - if ((retval & DM_RET_ACTION_MASK) != DM_RET_NONE) - return(retval); - } + if (cur_pattern->flags == DEV_MATCH_ANY) + goto copy_dev_node; /* * Not sure why someone would do this... @@ -1292,11 +1323,22 @@ xptdevicematch(struct dev_match_pattern *patterns, u_int num_patterns, if (((cur_pattern->flags & DEV_MATCH_INQUIRY) != 0) && (cam_quirkmatch((caddr_t)&device->inq_data, - (caddr_t)&cur_pattern->inq_pat, - 1, sizeof(cur_pattern->inq_pat), + (caddr_t)&cur_pattern->data.inq_pat, + 1, sizeof(cur_pattern->data.inq_pat), scsi_static_inquiry_match) == NULL)) continue; + device_id_page = (struct scsi_vpd_device_id *)device->device_id; + if (((cur_pattern->flags & DEV_MATCH_DEVID) != 0) + && (device->device_id_len < SVPD_DEVICE_ID_HDR_LEN + || scsi_devid_match((uint8_t *)device_id_page->desc_list, + device->device_id_len + - SVPD_DEVICE_ID_HDR_LEN, + cur_pattern->data.devid_pat.id, + cur_pattern->data.devid_pat.id_len) != 0)) + continue; + +copy_dev_node: /* * If we get to this point, the user definitely wants * information on this device. So tell the caller to copy @@ -2889,6 +2931,8 @@ xpt_action_default(union ccb *start_ccb) case XPT_TERM_IO: case XPT_ENG_INQ: /* XXX Implement */ + printf("%s: CCB type %#x not supported\n", __func__, + start_ccb->ccb_h.func_code); start_ccb->ccb_h.status = CAM_PROVIDE_FAIL; if (start_ccb->ccb_h.func_code & XPT_FC_DEV_QUEUED) { xpt_done(start_ccb); @@ -3528,16 +3572,12 @@ xpt_path_string(struct cam_path *path, char *str, size_t str_len) path_id_t xpt_path_path_id(struct cam_path *path) { - mtx_assert(path->bus->sim->mtx, MA_OWNED); - return(path->bus->path_id); } target_id_t xpt_path_target_id(struct cam_path *path) { - mtx_assert(path->bus->sim->mtx, MA_OWNED); - if (path->target != NULL) return (path->target->target_id); else @@ -3547,8 +3587,6 @@ xpt_path_target_id(struct cam_path *path) lun_id_t xpt_path_lun_id(struct cam_path *path) { - mtx_assert(path->bus->sim->mtx, MA_OWNED); - if (path->device != NULL) return (path->device->lun_id); else @@ -4242,7 +4280,8 @@ xpt_alloc_target(struct cam_eb *bus, target_id_t target_id) { struct cam_et *target; - target = (struct cam_et *)malloc(sizeof(*target), M_CAMXPT, M_NOWAIT); + target = (struct cam_et *)malloc(sizeof(*target), M_CAMXPT, + M_NOWAIT|M_ZERO); if (target != NULL) { struct cam_et *cur_target; @@ -4330,7 +4369,7 @@ xpt_alloc_device(struct cam_eb *bus, struct cam_et *target, lun_id_t lun_id) device = NULL; } else { device = (struct cam_ed *)malloc(sizeof(*device), - M_CAMXPT, M_NOWAIT); + M_CAMXPT, M_NOWAIT|M_ZERO); } if (device != NULL) { @@ -4676,27 +4715,29 @@ xpt_register_async(int event, ac_callback_t *cbfunc, void *cbarg, csa.callback_arg = cbarg; xpt_action((union ccb *)&csa); status = csa.ccb_h.status; + if (xptpath) { xpt_free_path(path); mtx_unlock(&xsoftc.xpt_lock); + } - if ((status == CAM_REQ_CMP) && - (csa.event_enable & AC_FOUND_DEVICE)) { - /* - * Get this peripheral up to date with all - * the currently existing devices. - */ - xpt_for_all_devices(xptsetasyncfunc, &csa); - } - if ((status == CAM_REQ_CMP) && - (csa.event_enable & AC_PATH_REGISTERED)) { - /* - * Get this peripheral up to date with all - * the currently existing busses. - */ - xpt_for_all_busses(xptsetasyncbusfunc, &csa); - } + if ((status == CAM_REQ_CMP) && + (csa.event_enable & AC_FOUND_DEVICE)) { + /* + * Get this peripheral up to date with all + * the currently existing devices. + */ + xpt_for_all_devices(xptsetasyncfunc, &csa); } + if ((status == CAM_REQ_CMP) && + (csa.event_enable & AC_PATH_REGISTERED)) { + /* + * Get this peripheral up to date with all + * the currently existing busses. + */ + xpt_for_all_busses(xptsetasyncbusfunc, &csa); + } + return (status); } @@ -4852,8 +4893,10 @@ camisr_runqueue(void *V_queue) if ((dev->flags & CAM_DEV_TAG_AFTER_COUNT) != 0 && (--dev->tag_delay_count == 0)) xpt_start_tags(ccb_h->path); - if (!device_is_send_queued(dev)) - xpt_schedule_dev_sendq(ccb_h->path->bus, dev); + if (!device_is_send_queued(dev)) { + runq = xpt_schedule_dev_sendq(ccb_h->path->bus, + dev); + } } if (ccb_h->status & CAM_RELEASE_SIMQ) { diff --git a/sys/cam/cam_xpt.h b/sys/cam/cam_xpt.h index 9355be4..f7d9b42 100644 --- a/sys/cam/cam_xpt.h +++ b/sys/cam/cam_xpt.h @@ -103,6 +103,8 @@ cam_status xpt_create_path_unlocked(struct cam_path **new_path_ptr, struct cam_periph *perph, path_id_t path_id, target_id_t target_id, lun_id_t lun_id); +int xpt_getattr(char *buf, size_t len, const char *attr, + struct cam_path *path); void xpt_free_path(struct cam_path *path); int xpt_path_comp(struct cam_path *path1, struct cam_path *path2); diff --git a/sys/cam/cam_xpt_internal.h b/sys/cam/cam_xpt_internal.h index f485e37..b6e8f66 100644 --- a/sys/cam/cam_xpt_internal.h +++ b/sys/cam/cam_xpt_internal.h @@ -97,6 +97,8 @@ struct cam_ed { uint8_t supported_vpds_len; uint32_t device_id_len; uint8_t *device_id; + uint8_t physpath_len; + uint8_t *physpath; /* physical path string form */ struct ata_params ident_data; u_int8_t inq_flags; /* * Current settings for inquiry flags. diff --git a/sys/cam/scsi/scsi_all.c b/sys/cam/scsi/scsi_all.c index 7ededa1..7361c42 100644 --- a/sys/cam/scsi/scsi_all.c +++ b/sys/cam/scsi/scsi_all.c @@ -3552,32 +3552,63 @@ scsi_calc_syncparam(u_int period) return (period/400); } -uint8_t * -scsi_get_sas_addr(struct scsi_vpd_device_id *id, uint32_t len) +int +scsi_devid_is_naa_ieee_reg(uint8_t *bufp) { - uint8_t *bufp, *buf_end; struct scsi_vpd_id_descriptor *descr; struct scsi_vpd_id_naa_basic *naa; - bufp = buf_end = (uint8_t *)id; - bufp += SVPD_DEVICE_ID_HDR_LEN; - buf_end += len; - while (bufp < buf_end) { - descr = (struct scsi_vpd_id_descriptor *)bufp; - bufp += SVPD_DEVICE_ID_DESC_HDR_LEN; - /* Right now, we only care about SAS NAA IEEE Reg addrs */ - if (((descr->id_type & SVPD_ID_PIV) != 0) - && (descr->proto_codeset >> SVPD_ID_PROTO_SHIFT) == - SCSI_PROTO_SAS - && (descr->id_type & SVPD_ID_TYPE_MASK) == SVPD_ID_TYPE_NAA){ - naa = (struct scsi_vpd_id_naa_basic *)bufp; - if ((naa->naa >> 4) == SVPD_ID_NAA_IEEE_REG) - return bufp; - } - bufp += descr->length; + descr = (struct scsi_vpd_id_descriptor *)bufp; + naa = (struct scsi_vpd_id_naa_basic *)descr->identifier; + if ((descr->id_type & SVPD_ID_TYPE_MASK) != SVPD_ID_TYPE_NAA) + return 0; + if (descr->length < sizeof(struct scsi_vpd_id_naa_ieee_reg)) + return 0; + if ((naa->naa >> SVPD_ID_NAA_NAA_SHIFT) != SVPD_ID_NAA_IEEE_REG) + return 0; + return 1; +} + +int +scsi_devid_is_sas_target(uint8_t *bufp) +{ + struct scsi_vpd_id_descriptor *descr; + + descr = (struct scsi_vpd_id_descriptor *)bufp; + if (!scsi_devid_is_naa_ieee_reg(bufp)) + return 0; + if ((descr->id_type & SVPD_ID_PIV) == 0) /* proto field reserved */ + return 0; + if ((descr->proto_codeset >> SVPD_ID_PROTO_SHIFT) != SCSI_PROTO_SAS) + return 0; + return 1; +} + +uint8_t * +scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t page_len, + scsi_devid_checkfn_t ck_fn) +{ + struct scsi_vpd_id_descriptor *desc; + uint8_t *page_end; + uint8_t *desc_buf_end; + + page_end = (uint8_t *)id + page_len; + if (page_end < id->desc_list) + return (NULL); + + desc_buf_end = MIN(id->desc_list + scsi_2btoul(id->length), page_end); + + for (desc = (struct scsi_vpd_id_descriptor *)id->desc_list; + desc->identifier <= desc_buf_end + && desc->identifier + desc->length <= desc_buf_end; + desc = (struct scsi_vpd_id_descriptor *)(desc->identifier + + desc->length)) { + + if (ck_fn == NULL || ck_fn((uint8_t *)desc) != 0) + return (desc->identifier); } - return NULL; + return (NULL); } void @@ -4174,6 +4205,77 @@ scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries, timeout); } +void +scsi_receive_diagnostic_results(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb*), + uint8_t tag_action, int pcv, uint8_t page_code, + uint8_t *data_ptr, uint16_t allocation_length, + uint8_t sense_len, uint32_t timeout) +{ + struct scsi_receive_diag *scsi_cmd; + + scsi_cmd = (struct scsi_receive_diag *)&csio->cdb_io.cdb_bytes; + memset(scsi_cmd, 0, sizeof(*scsi_cmd)); + scsi_cmd->opcode = RECEIVE_DIAGNOSTIC; + if (pcv) { + scsi_cmd->byte2 |= SRD_PCV; + scsi_cmd->page_code = page_code; + } + scsi_ulto2b(allocation_length, scsi_cmd->length); + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/CAM_DIR_IN, + tag_action, + data_ptr, + allocation_length, + sense_len, + sizeof(*scsi_cmd), + timeout); +} + +void +scsi_send_diagnostic(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + uint8_t tag_action, int unit_offline, int device_offline, + int self_test, int page_format, int self_test_code, + uint8_t *data_ptr, uint16_t param_list_length, + uint8_t sense_len, uint32_t timeout) +{ + struct scsi_send_diag *scsi_cmd; + + scsi_cmd = (struct scsi_send_diag *)&csio->cdb_io.cdb_bytes; + memset(scsi_cmd, 0, sizeof(*scsi_cmd)); + scsi_cmd->opcode = SEND_DIAGNOSTIC; + + /* + * The default self-test mode control and specific test + * control are mutually exclusive. + */ + if (self_test) + self_test_code = SSD_SELF_TEST_CODE_NONE; + + scsi_cmd->byte2 = ((self_test_code << SSD_SELF_TEST_CODE_SHIFT) + & SSD_SELF_TEST_CODE_MASK) + | (unit_offline ? SSD_UNITOFFL : 0) + | (device_offline ? SSD_DEVOFFL : 0) + | (self_test ? SSD_SELFTEST : 0) + | (page_format ? SSD_PF : 0); + scsi_ulto2b(param_list_length, scsi_cmd->length); + + cam_fill_csio(csio, + retries, + cbfcnp, + /*flags*/param_list_length ? CAM_DIR_OUT : CAM_DIR_NONE, + tag_action, + data_ptr, + param_list_length, + sense_len, + sizeof(*scsi_cmd), + timeout); +} + void scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), @@ -4206,7 +4308,6 @@ scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, sense_len, sizeof(*scsi_cmd), timeout); - } @@ -4264,6 +4365,66 @@ scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) return (-1); } +/** + * Compare two buffers of vpd device descriptors for a match. + * + * \param lhs Pointer to first buffer of descriptors to compare. + * \param lhs_len The length of the first buffer. + * \param rhs Pointer to second buffer of descriptors to compare. + * \param rhs_len The length of the second buffer. + * + * \return 0 on a match, -1 otherwise. + * + * Treat rhs and lhs as arrays of vpd device id descriptors. Walk lhs matching + * agains each element in rhs until all data are exhausted or we have found + * a match. + */ +int +scsi_devid_match(uint8_t *lhs, size_t lhs_len, uint8_t *rhs, size_t rhs_len) +{ + struct scsi_vpd_id_descriptor *lhs_id; + struct scsi_vpd_id_descriptor *lhs_last; + struct scsi_vpd_id_descriptor *rhs_last; + uint8_t *lhs_end; + uint8_t *rhs_end; + + lhs_end = lhs + lhs_len; + rhs_end = rhs + rhs_len; + + /* + * rhs_last and lhs_last are the last posible position of a valid + * descriptor assuming it had a zero length identifier. We use + * these variables to insure we can safely dereference the length + * field in our loop termination tests. + */ + lhs_last = (struct scsi_vpd_id_descriptor *) + (lhs_end - __offsetof(struct scsi_vpd_id_descriptor, identifier)); + rhs_last = (struct scsi_vpd_id_descriptor *) + (rhs_end - __offsetof(struct scsi_vpd_id_descriptor, identifier)); + + lhs_id = (struct scsi_vpd_id_descriptor *)lhs; + while (lhs_id <= lhs_last + && (lhs_id->identifier + lhs_id->length) <= lhs_end) { + struct scsi_vpd_id_descriptor *rhs_id; + + rhs_id = (struct scsi_vpd_id_descriptor *)rhs; + while (rhs_id <= rhs_last + && (rhs_id->identifier + rhs_id->length) <= rhs_end) { + + if (rhs_id->length == lhs_id->length + && memcmp(rhs_id->identifier, lhs_id->identifier, + rhs_id->length) == 0) + return (0); + + rhs_id = (struct scsi_vpd_id_descriptor *) + (rhs_id->identifier + rhs_id->length); + } + lhs_id = (struct scsi_vpd_id_descriptor *) + (lhs_id->identifier + lhs_id->length); + } + return (-1); +} + #ifdef _KERNEL static void init_scsi_delay(void) diff --git a/sys/cam/scsi/scsi_all.h b/sys/cam/scsi/scsi_all.h index 0a7a58f..93b11d5 100644 --- a/sys/cam/scsi/scsi_all.h +++ b/sys/cam/scsi/scsi_all.h @@ -115,6 +115,7 @@ struct scsi_request_sense { u_int8_t opcode; u_int8_t byte2; +#define SRS_DESC 0x01 u_int8_t unused[2]; u_int8_t length; u_int8_t control; @@ -128,17 +129,33 @@ struct scsi_test_unit_ready u_int8_t control; }; -struct scsi_send_diag -{ - u_int8_t opcode; - u_int8_t byte2; -#define SSD_UOL 0x01 -#define SSD_DOL 0x02 -#define SSD_SELFTEST 0x04 -#define SSD_PF 0x10 - u_int8_t unused[1]; - u_int8_t paramlen[2]; - u_int8_t control; +struct scsi_receive_diag { + uint8_t opcode; + uint8_t byte2; +#define SRD_PCV 0x01 + uint8_t page_code; + uint8_t length[2]; + uint8_t control; +}; + +struct scsi_send_diag { + uint8_t opcode; + uint8_t byte2; +#define SSD_UNITOFFL 0x01 +#define SSD_DEVOFFL 0x02 +#define SSD_SELFTEST 0x04 +#define SSD_PF 0x10 +#define SSD_SELF_TEST_CODE_MASK 0xE0 +#define SSD_SELF_TEST_CODE_SHIFT 5 +#define SSD_SELF_TEST_CODE_NONE 0x00 +#define SSD_SELF_TEST_CODE_BG_SHORT 0x01 +#define SSD_SELF_TEST_CODE_BG_EXTENDED 0x02 +#define SSD_SELF_TEST_CODE_BG_ABORT 0x04 +#define SSD_SELF_TEST_CODE_FG_SHORT 0x05 +#define SSD_SELF_TEST_CODE_FG_EXTENDED 0x06 + uint8_t reserved; + uint8_t length[2]; + uint8_t control; }; struct scsi_sense @@ -894,11 +911,12 @@ struct scsi_vpd_id_naa_basic uint8_t naa : 4; uint8_t naa_desig : 4; */ +#define SVPD_ID_NAA_NAA_SHIFT 4 #define SVPD_ID_NAA_IEEE_EXT 0x02 #define SVPD_ID_NAA_LOCAL_REG 0x03 #define SVPD_ID_NAA_IEEE_REG 0x05 #define SVPD_ID_NAA_IEEE_REG_EXT 0x06 - uint8_t naa_data[0]; + uint8_t naa_data[]; }; struct scsi_vpd_id_naa_ieee_extended_id @@ -1322,7 +1340,12 @@ void scsi_print_inquiry(struct scsi_inquiry_data *inq_data); u_int scsi_calc_syncsrate(u_int period_factor); u_int scsi_calc_syncparam(u_int period); -uint8_t * scsi_get_sas_addr(struct scsi_vpd_device_id *id, uint32_t len); + +typedef int (*scsi_devid_checkfn_t)(uint8_t *); +int scsi_devid_is_naa_ieee_reg(uint8_t *bufp); +int scsi_devid_is_sas_target(uint8_t *bufp); +uint8_t * scsi_get_devid(struct scsi_vpd_device_id *id, uint32_t len, + scsi_devid_checkfn_t ck_fn); void scsi_test_unit_ready(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, @@ -1439,6 +1462,22 @@ void scsi_synchronize_cache(struct ccb_scsiio *csio, u_int32_t begin_lba, u_int16_t lb_count, u_int8_t sense_len, u_int32_t timeout); +void scsi_receive_diagnostic_results(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, + union ccb*), + uint8_t tag_action, int pcv, + uint8_t page_code, uint8_t *data_ptr, + uint16_t allocation_length, + uint8_t sense_len, uint32_t timeout); + +void scsi_send_diagnostic(struct ccb_scsiio *csio, u_int32_t retries, + void (*cbfcnp)(struct cam_periph *, union ccb *), + uint8_t tag_action, int unit_offline, + int device_offline, int self_test, int page_format, + int self_test_code, uint8_t *data_ptr, + uint16_t param_list_length, uint8_t sense_len, + uint32_t timeout); + void scsi_read_write(struct ccb_scsiio *csio, u_int32_t retries, void (*cbfcnp)(struct cam_periph *, union ccb *), u_int8_t tag_action, int readop, u_int8_t byte2, @@ -1455,6 +1494,8 @@ void scsi_start_stop(struct ccb_scsiio *csio, u_int32_t retries, int scsi_inquiry_match(caddr_t inqbuffer, caddr_t table_entry); int scsi_static_inquiry_match(caddr_t inqbuffer, caddr_t table_entry); +int scsi_devid_match(uint8_t *rhs, size_t rhs_len, + uint8_t *lhs, size_t lhs_len); static __inline void scsi_extract_sense(struct scsi_sense_data *sense, int *error_code, int *sense_key, diff --git a/sys/cam/scsi/scsi_pass.c b/sys/cam/scsi/scsi_pass.c index e7ecb35..5b24d82 100644 --- a/sys/cam/scsi/scsi_pass.c +++ b/sys/cam/scsi/scsi_pass.c @@ -548,8 +548,8 @@ passsendccb(struct cam_periph *periph, union ccb *ccb, union ccb *inccb) && ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE)) || (ccb->ccb_h.func_code == XPT_DEV_MATCH) || (ccb->ccb_h.func_code == XPT_SMP_IO) - || ((ccb->ccb_h.func_code == XPT_GDEV_ADVINFO) - && (ccb->cgdai.bufsiz > 0)))) { + || ((ccb->ccb_h.func_code == XPT_DEV_ADVINFO) + && (ccb->cdai.bufsiz > 0)))) { bzero(&mapinfo, sizeof(mapinfo)); diff --git a/sys/cam/scsi/scsi_xpt.c b/sys/cam/scsi/scsi_xpt.c index 2a38128..1b507ca 100644 --- a/sys/cam/scsi/scsi_xpt.c +++ b/sys/cam/scsi/scsi_xpt.c @@ -542,6 +542,7 @@ static const int scsi_quirk_table_size = static cam_status proberegister(struct cam_periph *periph, void *arg); static void probeschedule(struct cam_periph *probe_periph); +static int device_has_vpd(struct cam_ed *device, uint8_t page_id); static void probestart(struct cam_periph *periph, union ccb *start_ccb); static void proberequestdefaultnegotiation(struct cam_periph *periph); static int proberequestbackoff(struct cam_periph *periph, @@ -1460,7 +1461,7 @@ probedone(struct cam_periph *periph, union ccb *done_ccb) path->device->device_id = (uint8_t *)devid; } } else if (cam_periph_error(done_ccb, 0, - SF_RETRY_UA|SF_NO_PRINT, + SF_RETRY_UA, &softc->saved_ccb) == ERESTART) { return; } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { @@ -1506,9 +1507,9 @@ probe_device_check: (u_int8_t *)malloc((serial_buf->length + 1), M_CAMXPT, M_NOWAIT); if (path->device->serial_num != NULL) { - bcopy(serial_buf->serial_num, - path->device->serial_num, - serial_buf->length); + memcpy(path->device->serial_num, + serial_buf->serial_num, + serial_buf->length); path->device->serial_num_len = serial_buf->length; path->device->serial_num[serial_buf->length] @@ -2433,28 +2434,77 @@ scsi_devise_transport(struct cam_path *path) } static void -scsi_getdev_advinfo(union ccb *start_ccb) +scsi_dev_advinfo(union ccb *start_ccb) { struct cam_ed *device; - struct ccb_getdev_advinfo *cgdai; + struct ccb_dev_advinfo *cdai; off_t amt; device = start_ccb->ccb_h.path->device; - cgdai = &start_ccb->cgdai; - switch(cgdai->buftype) { - case CGDAI_TYPE_SCSI_DEVID: - cgdai->provsiz = device->device_id_len; + cdai = &start_ccb->cdai; + switch(cdai->buftype) { + case CDAI_TYPE_SCSI_DEVID: + if (cdai->flags & CDAI_FLAG_STORE) + break; + cdai->provsiz = device->device_id_len; if (device->device_id_len == 0) break; amt = device->device_id_len; - if (cgdai->provsiz > cgdai->bufsiz) - amt = cgdai->bufsiz; - bcopy(device->device_id, cgdai->buf, amt); + if (cdai->provsiz > cdai->bufsiz) + amt = cdai->bufsiz; + memcpy(cdai->buf, device->device_id, amt); + break; + case CDAI_TYPE_SERIAL_NUM: + if (cdai->flags & CDAI_FLAG_STORE) + break; + cdai->provsiz = device->serial_num_len; + if (device->serial_num_len == 0) + break; + amt = device->serial_num_len; + if (cdai->provsiz > cdai->bufsiz) + amt = cdai->bufsiz; + memcpy(cdai->buf, device->serial_num, amt); + break; + case CDAI_TYPE_PHYS_PATH: + if (cdai->flags & CDAI_FLAG_STORE) { + if (device->physpath != NULL) + free(device->physpath, M_CAMXPT); + device->physpath_len = cdai->bufsiz; + /* Clear existing buffer if zero length */ + if (cdai->bufsiz == 0) + break; + device->physpath = malloc(cdai->bufsiz, M_CAMXPT, M_NOWAIT); + if (device->physpath == NULL) { + start_ccb->ccb_h.status = CAM_REQ_ABORTED; + return; + } + memcpy(device->physpath, cdai->buf, cdai->bufsiz); + } else { + cdai->provsiz = device->physpath_len; + if (device->physpath_len == 0) + break; + amt = device->physpath_len; + if (cdai->provsiz > cdai->bufsiz) + amt = cdai->bufsiz; + memcpy(cdai->buf, device->physpath, amt); + } break; default: break; } start_ccb->ccb_h.status = CAM_REQ_CMP; + + if (cdai->flags & CDAI_FLAG_STORE) { + int owned; + + owned = mtx_owned(start_ccb->ccb_h.path->bus->sim->mtx); + if (owned == 0) + mtx_lock(start_ccb->ccb_h.path->bus->sim->mtx); + xpt_async(AC_ADVINFO_CHANGED, start_ccb->ccb_h.path, + (void *)(uintptr_t)cdai->buftype); + if (owned == 0) + mtx_unlock(start_ccb->ccb_h.path->bus->sim->mtx); + } } static void @@ -2486,9 +2536,9 @@ scsi_action(union ccb *start_ccb) (*(sim->sim_action))(sim, start_ccb); break; } - case XPT_GDEV_ADVINFO: + case XPT_DEV_ADVINFO: { - scsi_getdev_advinfo(start_ccb); + scsi_dev_advinfo(start_ccb); break; } default: |