1198389Smav/*- 2198389Smav * Copyright (c) 2009 Alexander Motin <mav@FreeBSD.org> 3198389Smav * All rights reserved. 4198389Smav * 5198389Smav * Redistribution and use in source and binary forms, with or without 6198389Smav * modification, are permitted provided that the following conditions 7198389Smav * are met: 8198389Smav * 1. Redistributions of source code must retain the above copyright 9198389Smav * notice, this list of conditions and the following disclaimer, 10198389Smav * without modification, immediately at the beginning of the file. 11198389Smav * 2. Redistributions in binary form must reproduce the above copyright 12198389Smav * notice, this list of conditions and the following disclaimer in the 13198389Smav * documentation and/or other materials provided with the distribution. 14198389Smav * 15198389Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16198389Smav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17198389Smav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18198389Smav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19198389Smav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20198389Smav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21198389Smav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22198389Smav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23198389Smav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24198389Smav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25198389Smav */ 26198389Smav 27198389Smav#include <sys/cdefs.h> 28198389Smav__FBSDID("$FreeBSD: releng/10.3/sys/cam/ata/ata_pmp.c 290768 2015-11-13 10:34:14Z mav $"); 29198389Smav 30198389Smav#include <sys/param.h> 31198389Smav 32198389Smav#ifdef _KERNEL 33198389Smav#include <sys/systm.h> 34198389Smav#include <sys/kernel.h> 35198389Smav#include <sys/bio.h> 36198389Smav#include <sys/sysctl.h> 37198389Smav#include <sys/taskqueue.h> 38198389Smav#include <sys/lock.h> 39198389Smav#include <sys/mutex.h> 40198389Smav#include <sys/conf.h> 41198389Smav#include <sys/devicestat.h> 42198389Smav#include <sys/eventhandler.h> 43198389Smav#include <sys/malloc.h> 44198389Smav#include <sys/cons.h> 45198389Smav#include <geom/geom_disk.h> 46198389Smav#endif /* _KERNEL */ 47198389Smav 48198389Smav#ifndef _KERNEL 49198389Smav#include <stdio.h> 50198389Smav#include <string.h> 51198389Smav#endif /* _KERNEL */ 52198389Smav 53198389Smav#include <cam/cam.h> 54198389Smav#include <cam/cam_ccb.h> 55198389Smav#include <cam/cam_periph.h> 56198389Smav#include <cam/cam_xpt_periph.h> 57200218Smav#include <cam/cam_xpt_internal.h> 58198389Smav#include <cam/cam_sim.h> 59198389Smav 60198389Smav#include <cam/ata/ata_all.h> 61198389Smav 62198389Smav#ifdef _KERNEL 63198389Smav 64198389Smavtypedef enum { 65198389Smav PMP_STATE_NORMAL, 66198389Smav PMP_STATE_PORTS, 67250508Smav PMP_STATE_PM_QUIRKS_1, 68250508Smav PMP_STATE_PM_QUIRKS_2, 69250508Smav PMP_STATE_PM_QUIRKS_3, 70199321Smav PMP_STATE_PRECONFIG, 71198389Smav PMP_STATE_RESET, 72198389Smav PMP_STATE_CONNECT, 73198389Smav PMP_STATE_CHECK, 74198389Smav PMP_STATE_CLEAR, 75199321Smav PMP_STATE_CONFIG, 76198389Smav PMP_STATE_SCAN 77198389Smav} pmp_state; 78198389Smav 79198389Smavtypedef enum { 80198389Smav PMP_FLAG_SCTX_INIT = 0x200 81198389Smav} pmp_flags; 82198389Smav 83198389Smavtypedef enum { 84198389Smav PMP_CCB_PROBE = 0x01, 85198389Smav} pmp_ccb_state; 86198389Smav 87198389Smav/* Offsets into our private area for storing information */ 88198389Smav#define ccb_state ppriv_field0 89198389Smav#define ccb_bp ppriv_ptr1 90198389Smav 91198389Smavstruct pmp_softc { 92198389Smav SLIST_ENTRY(pmp_softc) links; 93198389Smav pmp_state state; 94198389Smav pmp_flags flags; 95198389Smav uint32_t pm_pid; 96198389Smav uint32_t pm_prv; 97198389Smav int pm_ports; 98198389Smav int pm_step; 99198389Smav int pm_try; 100198389Smav int found; 101198708Smav int reset; 102198389Smav int frozen; 103198708Smav int restart; 104203108Smav int events; 105203108Smav#define PMP_EV_RESET 1 106203108Smav#define PMP_EV_RESCAN 2 107207499Smav u_int caps; 108198389Smav struct task sysctl_task; 109198389Smav struct sysctl_ctx_list sysctl_ctx; 110198389Smav struct sysctl_oid *sysctl_tree; 111198389Smav}; 112198389Smav 113198389Smavstatic periph_init_t pmpinit; 114198389Smavstatic void pmpasync(void *callback_arg, u_int32_t code, 115198389Smav struct cam_path *path, void *arg); 116198389Smavstatic void pmpsysctlinit(void *context, int pending); 117198389Smavstatic periph_ctor_t pmpregister; 118198389Smavstatic periph_dtor_t pmpcleanup; 119198389Smavstatic periph_start_t pmpstart; 120198389Smavstatic periph_oninv_t pmponinvalidate; 121198389Smavstatic void pmpdone(struct cam_periph *periph, 122198389Smav union ccb *done_ccb); 123198389Smav 124198389Smav#ifndef PMP_DEFAULT_TIMEOUT 125198389Smav#define PMP_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 126198389Smav#endif 127198389Smav 128198389Smav#ifndef PMP_DEFAULT_RETRY 129198389Smav#define PMP_DEFAULT_RETRY 1 130198389Smav#endif 131198389Smav 132235982Smav#ifndef PMP_DEFAULT_HIDE_SPECIAL 133235982Smav#define PMP_DEFAULT_HIDE_SPECIAL 1 134235982Smav#endif 135235982Smav 136198389Smavstatic int pmp_retry_count = PMP_DEFAULT_RETRY; 137198389Smavstatic int pmp_default_timeout = PMP_DEFAULT_TIMEOUT; 138235982Smavstatic int pmp_hide_special = PMP_DEFAULT_HIDE_SPECIAL; 139198389Smav 140227309Sedstatic SYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD, 0, 141198389Smav "CAM Direct Access Disk driver"); 142198389SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RW, 143198389Smav &pmp_retry_count, 0, "Normal I/O retry count"); 144198389SmavTUNABLE_INT("kern.cam.pmp.retry_count", &pmp_retry_count); 145198389SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RW, 146198389Smav &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)"); 147198389SmavTUNABLE_INT("kern.cam.pmp.default_timeout", &pmp_default_timeout); 148235982SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, hide_special, CTLFLAG_RW, 149235982Smav &pmp_hide_special, 0, "Hide extra ports"); 150235982SmavTUNABLE_INT("kern.cam.pmp.hide_special", &pmp_hide_special); 151198389Smav 152198389Smavstatic struct periph_driver pmpdriver = 153198389Smav{ 154198389Smav pmpinit, "pmp", 155198708Smav TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0, 156198708Smav CAM_PERIPH_DRV_EARLY 157198389Smav}; 158198389Smav 159198389SmavPERIPHDRIVER_DECLARE(pmp, pmpdriver); 160198389Smav 161198389Smavstatic void 162198389Smavpmpinit(void) 163198389Smav{ 164198389Smav cam_status status; 165198389Smav 166198389Smav /* 167198389Smav * Install a global async callback. This callback will 168198389Smav * receive async callbacks like "new device found". 169198389Smav */ 170198389Smav status = xpt_register_async(AC_FOUND_DEVICE, pmpasync, NULL, NULL); 171198389Smav 172198389Smav if (status != CAM_REQ_CMP) { 173198389Smav printf("pmp: Failed to attach master async callback " 174198389Smav "due to status 0x%x!\n", status); 175198389Smav } 176198389Smav} 177198389Smav 178198389Smavstatic void 179198389Smavpmpfreeze(struct cam_periph *periph, int mask) 180198389Smav{ 181198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 182198389Smav struct cam_path *dpath; 183198389Smav int i; 184198389Smav 185198389Smav mask &= ~softc->frozen; 186198389Smav for (i = 0; i < 15; i++) { 187198389Smav if ((mask & (1 << i)) == 0) 188198389Smav continue; 189198389Smav if (xpt_create_path(&dpath, periph, 190198389Smav xpt_path_path_id(periph->path), 191198389Smav i, 0) == CAM_REQ_CMP) { 192198389Smav softc->frozen |= (1 << i); 193200218Smav xpt_acquire_device(dpath->device); 194249438Smav cam_freeze_devq(dpath); 195198389Smav xpt_free_path(dpath); 196198389Smav } 197198389Smav } 198198389Smav} 199198389Smav 200198389Smavstatic void 201198389Smavpmprelease(struct cam_periph *periph, int mask) 202198389Smav{ 203198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 204198389Smav struct cam_path *dpath; 205198389Smav int i; 206198389Smav 207198389Smav mask &= softc->frozen; 208198389Smav for (i = 0; i < 15; i++) { 209198389Smav if ((mask & (1 << i)) == 0) 210198389Smav continue; 211198389Smav if (xpt_create_path(&dpath, periph, 212198389Smav xpt_path_path_id(periph->path), 213198389Smav i, 0) == CAM_REQ_CMP) { 214198389Smav softc->frozen &= ~(1 << i); 215249438Smav cam_release_devq(dpath, 0, 0, 0, FALSE); 216200218Smav xpt_release_device(dpath->device); 217198389Smav xpt_free_path(dpath); 218198389Smav } 219198389Smav } 220198389Smav} 221198389Smav 222198389Smavstatic void 223198389Smavpmponinvalidate(struct cam_periph *periph) 224198389Smav{ 225198389Smav struct cam_path *dpath; 226198389Smav int i; 227198389Smav 228198389Smav /* 229198389Smav * De-register any async callbacks. 230198389Smav */ 231198389Smav xpt_register_async(0, pmpasync, periph, periph->path); 232198389Smav 233198389Smav for (i = 0; i < 15; i++) { 234198389Smav if (xpt_create_path(&dpath, periph, 235198389Smav xpt_path_path_id(periph->path), 236198389Smav i, 0) == CAM_REQ_CMP) { 237198389Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 238198389Smav xpt_free_path(dpath); 239198389Smav } 240198389Smav } 241200218Smav pmprelease(periph, -1); 242198389Smav} 243198389Smav 244198389Smavstatic void 245198389Smavpmpcleanup(struct cam_periph *periph) 246198389Smav{ 247198389Smav struct pmp_softc *softc; 248198389Smav 249198389Smav softc = (struct pmp_softc *)periph->softc; 250198389Smav 251198389Smav cam_periph_unlock(periph); 252198389Smav 253198389Smav /* 254198389Smav * If we can't free the sysctl tree, oh well... 255198389Smav */ 256198389Smav if ((softc->flags & PMP_FLAG_SCTX_INIT) != 0 257198389Smav && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 258198389Smav xpt_print(periph->path, "can't remove sysctl context\n"); 259198389Smav } 260198389Smav 261198389Smav free(softc, M_DEVBUF); 262198389Smav cam_periph_lock(periph); 263198389Smav} 264198389Smav 265198389Smavstatic void 266198389Smavpmpasync(void *callback_arg, u_int32_t code, 267198389Smav struct cam_path *path, void *arg) 268198389Smav{ 269198389Smav struct cam_periph *periph; 270198389Smav struct pmp_softc *softc; 271198389Smav 272198389Smav periph = (struct cam_periph *)callback_arg; 273198389Smav switch (code) { 274198389Smav case AC_FOUND_DEVICE: 275198389Smav { 276198389Smav struct ccb_getdev *cgd; 277198389Smav cam_status status; 278198389Smav 279198389Smav cgd = (struct ccb_getdev *)arg; 280198389Smav if (cgd == NULL) 281198389Smav break; 282198389Smav 283198389Smav if (cgd->protocol != PROTO_SATAPM) 284198389Smav break; 285198389Smav 286198389Smav /* 287198389Smav * Allocate a peripheral instance for 288198389Smav * this device and start the probe 289198389Smav * process. 290198389Smav */ 291198389Smav status = cam_periph_alloc(pmpregister, pmponinvalidate, 292198389Smav pmpcleanup, pmpstart, 293198389Smav "pmp", CAM_PERIPH_BIO, 294260387Sscottl path, pmpasync, 295198389Smav AC_FOUND_DEVICE, cgd); 296198389Smav 297198389Smav if (status != CAM_REQ_CMP 298198389Smav && status != CAM_REQ_INPROG) 299198389Smav printf("pmpasync: Unable to attach to new device " 300198389Smav "due to status 0x%x\n", status); 301198389Smav break; 302198389Smav } 303198389Smav case AC_SCSI_AEN: 304198389Smav case AC_SENT_BDR: 305198389Smav case AC_BUS_RESET: 306198389Smav softc = (struct pmp_softc *)periph->softc; 307198389Smav cam_periph_async(periph, code, path, arg); 308203108Smav if (code == AC_SCSI_AEN) 309203108Smav softc->events |= PMP_EV_RESCAN; 310203108Smav else 311203108Smav softc->events |= PMP_EV_RESET; 312203108Smav if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL) 313198389Smav break; 314203108Smav xpt_hold_boot(); 315203108Smav pmpfreeze(periph, softc->found); 316198389Smav if (code == AC_SENT_BDR || code == AC_BUS_RESET) 317198389Smav softc->found = 0; /* We have to reset everything. */ 318198708Smav if (softc->state == PMP_STATE_NORMAL) { 319260387Sscottl if (cam_periph_acquire(periph) == CAM_REQ_CMP) { 320260387Sscottl if (softc->pm_pid == 0x37261095 || 321260387Sscottl softc->pm_pid == 0x38261095) 322260387Sscottl softc->state = PMP_STATE_PM_QUIRKS_1; 323260387Sscottl else 324260387Sscottl softc->state = PMP_STATE_PRECONFIG; 325260387Sscottl xpt_schedule(periph, CAM_PRIORITY_DEV); 326260387Sscottl } else { 327260387Sscottl pmprelease(periph, softc->found); 328260387Sscottl xpt_release_boot(); 329260387Sscottl } 330198708Smav } else 331198708Smav softc->restart = 1; 332198389Smav break; 333198389Smav default: 334198389Smav cam_periph_async(periph, code, path, arg); 335198389Smav break; 336198389Smav } 337198389Smav} 338198389Smav 339198389Smavstatic void 340198389Smavpmpsysctlinit(void *context, int pending) 341198389Smav{ 342198389Smav struct cam_periph *periph; 343198389Smav struct pmp_softc *softc; 344198389Smav char tmpstr[80], tmpstr2[80]; 345198389Smav 346198389Smav periph = (struct cam_periph *)context; 347198389Smav if (cam_periph_acquire(periph) != CAM_REQ_CMP) 348198389Smav return; 349198389Smav 350198389Smav softc = (struct pmp_softc *)periph->softc; 351198389Smav snprintf(tmpstr, sizeof(tmpstr), "CAM PMP unit %d", periph->unit_number); 352198389Smav snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 353198389Smav 354198389Smav sysctl_ctx_init(&softc->sysctl_ctx); 355198389Smav softc->flags |= PMP_FLAG_SCTX_INIT; 356198389Smav softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 357198389Smav SYSCTL_STATIC_CHILDREN(_kern_cam_pmp), OID_AUTO, tmpstr2, 358198389Smav CTLFLAG_RD, 0, tmpstr); 359198389Smav if (softc->sysctl_tree == NULL) { 360198389Smav printf("pmpsysctlinit: unable to allocate sysctl tree\n"); 361198389Smav cam_periph_release(periph); 362198389Smav return; 363198389Smav } 364198389Smav 365198389Smav cam_periph_release(periph); 366198389Smav} 367198389Smav 368198389Smavstatic cam_status 369198389Smavpmpregister(struct cam_periph *periph, void *arg) 370198389Smav{ 371198389Smav struct pmp_softc *softc; 372198389Smav struct ccb_getdev *cgd; 373198389Smav 374198389Smav cgd = (struct ccb_getdev *)arg; 375198389Smav if (cgd == NULL) { 376198389Smav printf("pmpregister: no getdev CCB, can't register device\n"); 377198389Smav return(CAM_REQ_CMP_ERR); 378198389Smav } 379198389Smav 380198389Smav softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF, 381198389Smav M_NOWAIT|M_ZERO); 382198389Smav 383198389Smav if (softc == NULL) { 384198389Smav printf("pmpregister: Unable to probe new device. " 385198389Smav "Unable to allocate softc\n"); 386198389Smav return(CAM_REQ_CMP_ERR); 387198389Smav } 388198389Smav periph->softc = softc; 389198389Smav 390198389Smav softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0]; 391198389Smav softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1]; 392198389Smav TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph); 393198389Smav 394198389Smav xpt_announce_periph(periph, NULL); 395198389Smav 396198389Smav /* 397198389Smav * Add async callbacks for bus reset and 398198389Smav * bus device reset calls. I don't bother 399198389Smav * checking if this fails as, in most cases, 400198389Smav * the system will function just fine without 401198389Smav * them and the only alternative would be to 402198389Smav * not attach the device on failure. 403198389Smav */ 404198389Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 405198389Smav AC_SCSI_AEN, pmpasync, periph, periph->path); 406198389Smav 407198389Smav /* 408198389Smav * Take an exclusive refcount on the periph while pmpstart is called 409198389Smav * to finish the probe. The reference will be dropped in pmpdone at 410198389Smav * the end of probe. 411198389Smav */ 412198389Smav (void)cam_periph_acquire(periph); 413203108Smav xpt_hold_boot(); 414203108Smav softc->state = PMP_STATE_PORTS; 415203108Smav softc->events = PMP_EV_RESCAN; 416203108Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 417198389Smav 418198389Smav return(CAM_REQ_CMP); 419198389Smav} 420198389Smav 421198389Smavstatic void 422198389Smavpmpstart(struct cam_periph *periph, union ccb *start_ccb) 423198389Smav{ 424203108Smav struct ccb_trans_settings cts; 425198389Smav struct ccb_ataio *ataio; 426198389Smav struct pmp_softc *softc; 427203108Smav struct cam_path *dpath; 428203108Smav int revision = 0; 429198389Smav 430198389Smav softc = (struct pmp_softc *)periph->softc; 431198389Smav ataio = &start_ccb->ataio; 432236602Smav 433236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpstart\n")); 434236602Smav 435198708Smav if (softc->restart) { 436198708Smav softc->restart = 0; 437250508Smav if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095) 438250508Smav softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1); 439250508Smav else 440250508Smav softc->state = min(softc->state, PMP_STATE_PRECONFIG); 441198708Smav } 442203108Smav /* Fetch user wanted device speed. */ 443203108Smav if (softc->state == PMP_STATE_RESET || 444203108Smav softc->state == PMP_STATE_CONNECT) { 445203108Smav if (xpt_create_path(&dpath, periph, 446203108Smav xpt_path_path_id(periph->path), 447203108Smav softc->pm_step, 0) == CAM_REQ_CMP) { 448203108Smav bzero(&cts, sizeof(cts)); 449203108Smav xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 450203108Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 451203108Smav cts.type = CTS_TYPE_USER_SETTINGS; 452203108Smav xpt_action((union ccb *)&cts); 453203108Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_REVISION) 454203108Smav revision = cts.xport_specific.sata.revision; 455203108Smav xpt_free_path(dpath); 456203108Smav } 457203108Smav } 458198389Smav switch (softc->state) { 459198389Smav case PMP_STATE_PORTS: 460198389Smav cam_fill_ataio(ataio, 461198389Smav pmp_retry_count, 462198389Smav pmpdone, 463198389Smav /*flags*/CAM_DIR_NONE, 464198389Smav 0, 465198389Smav /*data_ptr*/NULL, 466198389Smav /*dxfer_len*/0, 467198389Smav pmp_default_timeout * 1000); 468198389Smav ata_pm_read_cmd(ataio, 2, 15); 469198389Smav break; 470250508Smav 471250508Smav case PMP_STATE_PM_QUIRKS_1: 472250508Smav case PMP_STATE_PM_QUIRKS_3: 473250508Smav cam_fill_ataio(ataio, 474250508Smav pmp_retry_count, 475250508Smav pmpdone, 476250508Smav /*flags*/CAM_DIR_NONE, 477250508Smav 0, 478250508Smav /*data_ptr*/NULL, 479250508Smav /*dxfer_len*/0, 480250508Smav pmp_default_timeout * 1000); 481250508Smav ata_pm_read_cmd(ataio, 129, 15); 482250508Smav break; 483250508Smav 484250508Smav case PMP_STATE_PM_QUIRKS_2: 485250508Smav cam_fill_ataio(ataio, 486250508Smav pmp_retry_count, 487250508Smav pmpdone, 488250508Smav /*flags*/CAM_DIR_NONE, 489250508Smav 0, 490250508Smav /*data_ptr*/NULL, 491250508Smav /*dxfer_len*/0, 492250508Smav pmp_default_timeout * 1000); 493250508Smav ata_pm_write_cmd(ataio, 129, 15, softc->caps & ~0x1); 494250508Smav break; 495250508Smav 496199321Smav case PMP_STATE_PRECONFIG: 497207499Smav /* Get/update host SATA capabilities. */ 498207499Smav bzero(&cts, sizeof(cts)); 499207499Smav xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE); 500207499Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 501207499Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 502207499Smav xpt_action((union ccb *)&cts); 503207499Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS) 504207499Smav softc->caps = cts.xport_specific.sata.caps; 505250508Smav else 506250508Smav softc->caps = 0; 507198389Smav cam_fill_ataio(ataio, 508198389Smav pmp_retry_count, 509198389Smav pmpdone, 510198389Smav /*flags*/CAM_DIR_NONE, 511198389Smav 0, 512198389Smav /*data_ptr*/NULL, 513198389Smav /*dxfer_len*/0, 514198389Smav pmp_default_timeout * 1000); 515199321Smav ata_pm_write_cmd(ataio, 0x60, 15, 0x0); 516198389Smav break; 517198389Smav case PMP_STATE_RESET: 518198389Smav cam_fill_ataio(ataio, 519198389Smav pmp_retry_count, 520198389Smav pmpdone, 521198389Smav /*flags*/CAM_DIR_NONE, 522198389Smav 0, 523198389Smav /*data_ptr*/NULL, 524198389Smav /*dxfer_len*/0, 525198389Smav pmp_default_timeout * 1000); 526198389Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 527203108Smav (revision << 4) | 528203108Smav ((softc->found & (1 << softc->pm_step)) ? 0 : 1)); 529198389Smav break; 530198389Smav case PMP_STATE_CONNECT: 531198389Smav cam_fill_ataio(ataio, 532198389Smav pmp_retry_count, 533198389Smav pmpdone, 534198389Smav /*flags*/CAM_DIR_NONE, 535198389Smav 0, 536198389Smav /*data_ptr*/NULL, 537198389Smav /*dxfer_len*/0, 538198389Smav pmp_default_timeout * 1000); 539203108Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 540203108Smav (revision << 4)); 541198389Smav break; 542198389Smav case PMP_STATE_CHECK: 543198389Smav cam_fill_ataio(ataio, 544198389Smav pmp_retry_count, 545198389Smav pmpdone, 546198389Smav /*flags*/CAM_DIR_NONE, 547198389Smav 0, 548198389Smav /*data_ptr*/NULL, 549198389Smav /*dxfer_len*/0, 550198389Smav pmp_default_timeout * 1000); 551198389Smav ata_pm_read_cmd(ataio, 0, softc->pm_step); 552198389Smav break; 553198389Smav case PMP_STATE_CLEAR: 554198708Smav softc->reset = 0; 555198389Smav cam_fill_ataio(ataio, 556198389Smav pmp_retry_count, 557198389Smav pmpdone, 558198389Smav /*flags*/CAM_DIR_NONE, 559198389Smav 0, 560198389Smav /*data_ptr*/NULL, 561198389Smav /*dxfer_len*/0, 562198389Smav pmp_default_timeout * 1000); 563198389Smav ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF); 564198389Smav break; 565199321Smav case PMP_STATE_CONFIG: 566199321Smav cam_fill_ataio(ataio, 567199321Smav pmp_retry_count, 568199321Smav pmpdone, 569199321Smav /*flags*/CAM_DIR_NONE, 570199321Smav 0, 571199321Smav /*data_ptr*/NULL, 572199321Smav /*dxfer_len*/0, 573199321Smav pmp_default_timeout * 1000); 574220602Smav ata_pm_write_cmd(ataio, 0x60, 15, 0x07 | 575220602Smav ((softc->caps & CTS_SATA_CAPS_H_AN) ? 0x08 : 0)); 576199321Smav break; 577198389Smav default: 578198389Smav break; 579198389Smav } 580198389Smav xpt_action(start_ccb); 581198389Smav} 582198389Smav 583198389Smavstatic void 584198389Smavpmpdone(struct cam_periph *periph, union ccb *done_ccb) 585198389Smav{ 586199747Smav struct ccb_trans_settings cts; 587198389Smav struct pmp_softc *softc; 588198389Smav struct ccb_ataio *ataio; 589220778Smav struct cam_path *dpath; 590198708Smav u_int32_t priority, res; 591203108Smav int i; 592198389Smav 593198389Smav softc = (struct pmp_softc *)periph->softc; 594198389Smav ataio = &done_ccb->ataio; 595198389Smav 596236602Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpdone\n")); 597198389Smav 598198389Smav priority = done_ccb->ccb_h.pinfo.priority; 599198389Smav 600198708Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 601203385Smav if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) { 602198389Smav return; 603198389Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 604198708Smav cam_release_devq(done_ccb->ccb_h.path, 605198708Smav /*relsim_flags*/0, 606198708Smav /*reduction*/0, 607198708Smav /*timeout*/0, 608198708Smav /*getcount_only*/0); 609198389Smav } 610198708Smav goto done; 611198708Smav } 612198708Smav 613198708Smav if (softc->restart) { 614198708Smav softc->restart = 0; 615198389Smav xpt_release_ccb(done_ccb); 616250508Smav if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095) 617250508Smav softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1); 618250508Smav else 619250508Smav softc->state = min(softc->state, PMP_STATE_PRECONFIG); 620198708Smav xpt_schedule(periph, priority); 621198708Smav return; 622198708Smav } 623198708Smav 624198708Smav switch (softc->state) { 625198708Smav case PMP_STATE_PORTS: 626220778Smav softc->pm_ports = (ataio->res.lba_high << 24) + 627220778Smav (ataio->res.lba_mid << 16) + 628220778Smav (ataio->res.lba_low << 8) + 629220778Smav ataio->res.sector_count; 630235982Smav if (pmp_hide_special) { 631235982Smav /* 632235982Smav * This PMP declares 6 ports, while only 5 of them 633235982Smav * are real. Port 5 is a SEMB port, probing which 634235982Smav * causes timeouts if external SEP is not connected 635235982Smav * to PMP over I2C. 636235982Smav */ 637247161Smav if ((softc->pm_pid == 0x37261095 || 638247161Smav softc->pm_pid == 0x38261095) && 639247161Smav softc->pm_ports == 6) 640235982Smav softc->pm_ports = 5; 641235982Smav 642235982Smav /* 643235982Smav * This PMP declares 7 ports, while only 5 of them 644235982Smav * are real. Port 5 is a fake "Config Disk" with 645235982Smav * 640 sectors size. Port 6 is a SEMB port. 646235982Smav */ 647235982Smav if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) 648235982Smav softc->pm_ports = 5; 649235982Smav 650235982Smav /* 651235982Smav * These PMPs have extra configuration port. 652235982Smav */ 653235982Smav if (softc->pm_pid == 0x57231095 || 654235982Smav softc->pm_pid == 0x57331095 || 655235982Smav softc->pm_pid == 0x57341095 || 656235982Smav softc->pm_pid == 0x57441095) 657235982Smav softc->pm_ports--; 658235982Smav } 659200218Smav printf("%s%d: %d fan-out ports\n", 660200218Smav periph->periph_name, periph->unit_number, 661200218Smav softc->pm_ports); 662250508Smav if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095) 663250508Smav softc->state = PMP_STATE_PM_QUIRKS_1; 664250508Smav else 665250508Smav softc->state = PMP_STATE_PRECONFIG; 666250508Smav xpt_release_ccb(done_ccb); 667250508Smav xpt_schedule(periph, priority); 668250508Smav return; 669250508Smav 670250508Smav case PMP_STATE_PM_QUIRKS_1: 671250508Smav softc->caps = (ataio->res.lba_high << 24) + 672250508Smav (ataio->res.lba_mid << 16) + 673250508Smav (ataio->res.lba_low << 8) + 674250508Smav ataio->res.sector_count; 675250508Smav if (softc->caps & 0x1) 676250508Smav softc->state = PMP_STATE_PM_QUIRKS_2; 677250508Smav else 678250508Smav softc->state = PMP_STATE_PRECONFIG; 679250508Smav xpt_release_ccb(done_ccb); 680250508Smav xpt_schedule(periph, priority); 681250508Smav return; 682250508Smav 683250508Smav case PMP_STATE_PM_QUIRKS_2: 684250508Smav if (bootverbose) 685250508Smav softc->state = PMP_STATE_PM_QUIRKS_3; 686250508Smav else 687250508Smav softc->state = PMP_STATE_PRECONFIG; 688250508Smav xpt_release_ccb(done_ccb); 689250508Smav xpt_schedule(periph, priority); 690250508Smav return; 691250508Smav 692250508Smav case PMP_STATE_PM_QUIRKS_3: 693250508Smav res = (ataio->res.lba_high << 24) + 694250508Smav (ataio->res.lba_mid << 16) + 695250508Smav (ataio->res.lba_low << 8) + 696250508Smav ataio->res.sector_count; 697250508Smav printf("%s%d: Disabling SiI3x26 R_OK in GSCR_POLL: %x->%x\n", 698250508Smav periph->periph_name, periph->unit_number, softc->caps, res); 699199321Smav softc->state = PMP_STATE_PRECONFIG; 700198708Smav xpt_release_ccb(done_ccb); 701198708Smav xpt_schedule(periph, priority); 702198708Smav return; 703250508Smav 704199321Smav case PMP_STATE_PRECONFIG: 705198708Smav softc->pm_step = 0; 706198708Smav softc->state = PMP_STATE_RESET; 707198708Smav softc->reset |= ~softc->found; 708198389Smav xpt_release_ccb(done_ccb); 709198708Smav xpt_schedule(periph, priority); 710198708Smav return; 711198389Smav case PMP_STATE_RESET: 712198708Smav softc->pm_step++; 713198708Smav if (softc->pm_step >= softc->pm_ports) { 714198708Smav softc->pm_step = 0; 715198708Smav cam_freeze_devq(periph->path); 716198708Smav cam_release_devq(periph->path, 717198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 718198708Smav /*reduction*/0, 719198708Smav /*timeout*/5, 720198708Smav /*getcount_only*/0); 721198708Smav softc->state = PMP_STATE_CONNECT; 722198389Smav } 723198389Smav xpt_release_ccb(done_ccb); 724198708Smav xpt_schedule(periph, priority); 725198708Smav return; 726198389Smav case PMP_STATE_CONNECT: 727198708Smav softc->pm_step++; 728198708Smav if (softc->pm_step >= softc->pm_ports) { 729198708Smav softc->pm_step = 0; 730198708Smav softc->pm_try = 0; 731198708Smav cam_freeze_devq(periph->path); 732198708Smav cam_release_devq(periph->path, 733198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 734198708Smav /*reduction*/0, 735198708Smav /*timeout*/10, 736198708Smav /*getcount_only*/0); 737198708Smav softc->state = PMP_STATE_CHECK; 738198389Smav } 739198389Smav xpt_release_ccb(done_ccb); 740198708Smav xpt_schedule(periph, priority); 741198708Smav return; 742198389Smav case PMP_STATE_CHECK: 743220778Smav res = (ataio->res.lba_high << 24) + 744220778Smav (ataio->res.lba_mid << 16) + 745220778Smav (ataio->res.lba_low << 8) + 746220778Smav ataio->res.sector_count; 747207499Smav if (((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) || 748207499Smav (res & 0x600) != 0) { 749200218Smav if (bootverbose) { 750200218Smav printf("%s%d: port %d status: %08x\n", 751200218Smav periph->periph_name, periph->unit_number, 752200218Smav softc->pm_step, res); 753200218Smav } 754207499Smav /* Report device speed if it is online. */ 755207499Smav if ((res & 0xf0f) == 0x103 && 756207499Smav xpt_create_path(&dpath, periph, 757199747Smav xpt_path_path_id(periph->path), 758199747Smav softc->pm_step, 0) == CAM_REQ_CMP) { 759199747Smav bzero(&cts, sizeof(cts)); 760203108Smav xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 761199747Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 762199747Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 763199747Smav cts.xport_specific.sata.revision = (res & 0x0f0) >> 4; 764199747Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION; 765207499Smav cts.xport_specific.sata.caps = softc->caps & 766220602Smav (CTS_SATA_CAPS_H_PMREQ | 767220602Smav CTS_SATA_CAPS_H_DMAAA | 768220602Smav CTS_SATA_CAPS_H_AN); 769207499Smav cts.xport_specific.sata.valid |= CTS_SATA_VALID_CAPS; 770199747Smav xpt_action((union ccb *)&cts); 771199747Smav xpt_free_path(dpath); 772199747Smav } 773198708Smav softc->found |= (1 << softc->pm_step); 774198708Smav softc->pm_step++; 775198708Smav } else { 776198708Smav if (softc->pm_try < 10) { 777198708Smav cam_freeze_devq(periph->path); 778198708Smav cam_release_devq(periph->path, 779198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 780198708Smav /*reduction*/0, 781198708Smav /*timeout*/10, 782198708Smav /*getcount_only*/0); 783198708Smav softc->pm_try++; 784198708Smav } else { 785200218Smav if (bootverbose) { 786200218Smav printf("%s%d: port %d status: %08x\n", 787200218Smav periph->periph_name, periph->unit_number, 788200218Smav softc->pm_step, res); 789200218Smav } 790198708Smav softc->found &= ~(1 << softc->pm_step); 791198708Smav if (xpt_create_path(&dpath, periph, 792198708Smav done_ccb->ccb_h.path_id, 793198708Smav softc->pm_step, 0) == CAM_REQ_CMP) { 794198708Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 795198708Smav xpt_free_path(dpath); 796198708Smav } 797198389Smav softc->pm_step++; 798198389Smav } 799198708Smav } 800198708Smav if (softc->pm_step >= softc->pm_ports) { 801198708Smav if (softc->reset & softc->found) { 802198708Smav cam_freeze_devq(periph->path); 803198708Smav cam_release_devq(periph->path, 804198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 805198708Smav /*reduction*/0, 806198708Smav /*timeout*/1000, 807198708Smav /*getcount_only*/0); 808198389Smav } 809198708Smav softc->state = PMP_STATE_CLEAR; 810198708Smav softc->pm_step = 0; 811198389Smav } 812198389Smav xpt_release_ccb(done_ccb); 813198708Smav xpt_schedule(periph, priority); 814198708Smav return; 815198389Smav case PMP_STATE_CLEAR: 816198708Smav softc->pm_step++; 817199321Smav if (softc->pm_step >= softc->pm_ports) { 818199321Smav softc->state = PMP_STATE_CONFIG; 819198708Smav softc->pm_step = 0; 820199321Smav } 821199321Smav xpt_release_ccb(done_ccb); 822199321Smav xpt_schedule(periph, priority); 823199321Smav return; 824199321Smav case PMP_STATE_CONFIG: 825203108Smav for (i = 0; i < softc->pm_ports; i++) { 826203108Smav union ccb *ccb; 827203108Smav 828203108Smav if ((softc->found & (1 << i)) == 0) 829203108Smav continue; 830203108Smav if (xpt_create_path(&dpath, periph, 831203108Smav xpt_path_path_id(periph->path), 832203108Smav i, 0) != CAM_REQ_CMP) { 833208819Smav printf("pmpdone: xpt_create_path failed\n"); 834208819Smav continue; 835203108Smav } 836203108Smav /* If we did hard reset to this device, inform XPT. */ 837203108Smav if ((softc->reset & softc->found & (1 << i)) != 0) 838203108Smav xpt_async(AC_SENT_BDR, dpath, NULL); 839203108Smav /* If rescan requested, scan this device. */ 840203108Smav if (softc->events & PMP_EV_RESCAN) { 841203108Smav ccb = xpt_alloc_ccb_nowait(); 842203108Smav if (ccb == NULL) { 843203108Smav xpt_free_path(dpath); 844203108Smav goto done; 845203108Smav } 846203108Smav xpt_setup_ccb(&ccb->ccb_h, dpath, CAM_PRIORITY_XPT); 847203108Smav xpt_rescan(ccb); 848203108Smav } else 849203108Smav xpt_free_path(dpath); 850198389Smav } 851198389Smav break; 852198389Smav default: 853198389Smav break; 854198389Smav } 855198708Smavdone: 856198708Smav xpt_release_ccb(done_ccb); 857198389Smav softc->state = PMP_STATE_NORMAL; 858203108Smav softc->events = 0; 859203108Smav xpt_release_boot(); 860198389Smav pmprelease(periph, -1); 861198389Smav cam_periph_release_locked(periph); 862198389Smav} 863198389Smav 864198389Smav#endif /* _KERNEL */ 865