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$"); 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, 67251096Smav PMP_STATE_PM_QUIRKS_1, 68251096Smav PMP_STATE_PM_QUIRKS_2, 69251096Smav 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 132236765Smav#ifndef PMP_DEFAULT_HIDE_SPECIAL 133236765Smav#define PMP_DEFAULT_HIDE_SPECIAL 1 134236765Smav#endif 135236765Smav 136198389Smavstatic int pmp_retry_count = PMP_DEFAULT_RETRY; 137198389Smavstatic int pmp_default_timeout = PMP_DEFAULT_TIMEOUT; 138236765Smavstatic int pmp_hide_special = PMP_DEFAULT_HIDE_SPECIAL; 139198389Smav 140248085Smariusstatic 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); 148236765SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, hide_special, CTLFLAG_RW, 149236765Smav &pmp_hide_special, 0, "Hide extra ports"); 150236765SmavTUNABLE_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 161249132Smavstatic MALLOC_DEFINE(M_ATPMP, "ata_pmp", "ata_pmp buffers"); 162198389Smav 163198389Smavstatic void 164198389Smavpmpinit(void) 165198389Smav{ 166198389Smav cam_status status; 167198389Smav 168198389Smav /* 169198389Smav * Install a global async callback. This callback will 170198389Smav * receive async callbacks like "new device found". 171198389Smav */ 172198389Smav status = xpt_register_async(AC_FOUND_DEVICE, pmpasync, NULL, NULL); 173198389Smav 174198389Smav if (status != CAM_REQ_CMP) { 175198389Smav printf("pmp: Failed to attach master async callback " 176198389Smav "due to status 0x%x!\n", status); 177198389Smav } 178198389Smav} 179198389Smav 180198389Smavstatic void 181198389Smavpmpfreeze(struct cam_periph *periph, int mask) 182198389Smav{ 183198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 184198389Smav struct cam_path *dpath; 185198389Smav int i; 186198389Smav 187198389Smav mask &= ~softc->frozen; 188198389Smav for (i = 0; i < 15; i++) { 189198389Smav if ((mask & (1 << i)) == 0) 190198389Smav continue; 191198389Smav if (xpt_create_path(&dpath, periph, 192198389Smav xpt_path_path_id(periph->path), 193198389Smav i, 0) == CAM_REQ_CMP) { 194198389Smav softc->frozen |= (1 << i); 195200218Smav xpt_acquire_device(dpath->device); 196256215Smav cam_freeze_devq(dpath); 197198389Smav xpt_free_path(dpath); 198198389Smav } 199198389Smav } 200198389Smav} 201198389Smav 202198389Smavstatic void 203198389Smavpmprelease(struct cam_periph *periph, int mask) 204198389Smav{ 205198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 206198389Smav struct cam_path *dpath; 207198389Smav int i; 208198389Smav 209198389Smav mask &= softc->frozen; 210198389Smav for (i = 0; i < 15; i++) { 211198389Smav if ((mask & (1 << i)) == 0) 212198389Smav continue; 213198389Smav if (xpt_create_path(&dpath, periph, 214198389Smav xpt_path_path_id(periph->path), 215198389Smav i, 0) == CAM_REQ_CMP) { 216198389Smav softc->frozen &= ~(1 << i); 217256215Smav cam_release_devq(dpath, 0, 0, 0, FALSE); 218200218Smav xpt_release_device(dpath->device); 219198389Smav xpt_free_path(dpath); 220198389Smav } 221198389Smav } 222198389Smav} 223198389Smav 224198389Smavstatic void 225198389Smavpmponinvalidate(struct cam_periph *periph) 226198389Smav{ 227198389Smav struct cam_path *dpath; 228198389Smav int i; 229198389Smav 230198389Smav /* 231198389Smav * De-register any async callbacks. 232198389Smav */ 233198389Smav xpt_register_async(0, pmpasync, periph, periph->path); 234198389Smav 235198389Smav for (i = 0; i < 15; i++) { 236198389Smav if (xpt_create_path(&dpath, periph, 237198389Smav xpt_path_path_id(periph->path), 238198389Smav i, 0) == CAM_REQ_CMP) { 239198389Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 240198389Smav xpt_free_path(dpath); 241198389Smav } 242198389Smav } 243200218Smav pmprelease(periph, -1); 244198389Smav} 245198389Smav 246198389Smavstatic void 247198389Smavpmpcleanup(struct cam_periph *periph) 248198389Smav{ 249198389Smav struct pmp_softc *softc; 250198389Smav 251198389Smav softc = (struct pmp_softc *)periph->softc; 252198389Smav 253198389Smav cam_periph_unlock(periph); 254198389Smav 255198389Smav /* 256198389Smav * If we can't free the sysctl tree, oh well... 257198389Smav */ 258198389Smav if ((softc->flags & PMP_FLAG_SCTX_INIT) != 0 259198389Smav && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 260198389Smav xpt_print(periph->path, "can't remove sysctl context\n"); 261198389Smav } 262198389Smav 263198389Smav free(softc, M_DEVBUF); 264198389Smav cam_periph_lock(periph); 265198389Smav} 266198389Smav 267198389Smavstatic void 268198389Smavpmpasync(void *callback_arg, u_int32_t code, 269198389Smav struct cam_path *path, void *arg) 270198389Smav{ 271198389Smav struct cam_periph *periph; 272198389Smav struct pmp_softc *softc; 273198389Smav 274198389Smav periph = (struct cam_periph *)callback_arg; 275198389Smav switch (code) { 276198389Smav case AC_FOUND_DEVICE: 277198389Smav { 278198389Smav struct ccb_getdev *cgd; 279198389Smav cam_status status; 280198389Smav 281198389Smav cgd = (struct ccb_getdev *)arg; 282198389Smav if (cgd == NULL) 283198389Smav break; 284198389Smav 285198389Smav if (cgd->protocol != PROTO_SATAPM) 286198389Smav break; 287198389Smav 288198389Smav /* 289198389Smav * Allocate a peripheral instance for 290198389Smav * this device and start the probe 291198389Smav * process. 292198389Smav */ 293198389Smav status = cam_periph_alloc(pmpregister, pmponinvalidate, 294198389Smav pmpcleanup, pmpstart, 295198389Smav "pmp", CAM_PERIPH_BIO, 296198389Smav cgd->ccb_h.path, pmpasync, 297198389Smav AC_FOUND_DEVICE, cgd); 298198389Smav 299198389Smav if (status != CAM_REQ_CMP 300198389Smav && status != CAM_REQ_INPROG) 301198389Smav printf("pmpasync: Unable to attach to new device " 302198389Smav "due to status 0x%x\n", status); 303198389Smav break; 304198389Smav } 305198389Smav case AC_SCSI_AEN: 306198389Smav case AC_SENT_BDR: 307198389Smav case AC_BUS_RESET: 308198389Smav softc = (struct pmp_softc *)periph->softc; 309198389Smav cam_periph_async(periph, code, path, arg); 310203108Smav if (code == AC_SCSI_AEN) 311203108Smav softc->events |= PMP_EV_RESCAN; 312203108Smav else 313203108Smav softc->events |= PMP_EV_RESET; 314203108Smav if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL) 315198389Smav break; 316203108Smav xpt_hold_boot(); 317203108Smav pmpfreeze(periph, softc->found); 318198389Smav if (code == AC_SENT_BDR || code == AC_BUS_RESET) 319198389Smav softc->found = 0; /* We have to reset everything. */ 320198708Smav if (softc->state == PMP_STATE_NORMAL) { 321251096Smav if (softc->pm_pid == 0x37261095 || 322251096Smav softc->pm_pid == 0x38261095) 323251096Smav softc->state = PMP_STATE_PM_QUIRKS_1; 324251096Smav else 325251096Smav softc->state = PMP_STATE_PRECONFIG; 326198708Smav cam_periph_acquire(periph); 327203108Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 328198708Smav } else 329198708Smav softc->restart = 1; 330198389Smav break; 331198389Smav default: 332198389Smav cam_periph_async(periph, code, path, arg); 333198389Smav break; 334198389Smav } 335198389Smav} 336198389Smav 337198389Smavstatic void 338198389Smavpmpsysctlinit(void *context, int pending) 339198389Smav{ 340198389Smav struct cam_periph *periph; 341198389Smav struct pmp_softc *softc; 342198389Smav char tmpstr[80], tmpstr2[80]; 343198389Smav 344198389Smav periph = (struct cam_periph *)context; 345198389Smav if (cam_periph_acquire(periph) != CAM_REQ_CMP) 346198389Smav return; 347198389Smav 348198389Smav softc = (struct pmp_softc *)periph->softc; 349198389Smav snprintf(tmpstr, sizeof(tmpstr), "CAM PMP unit %d", periph->unit_number); 350198389Smav snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 351198389Smav 352198389Smav sysctl_ctx_init(&softc->sysctl_ctx); 353198389Smav softc->flags |= PMP_FLAG_SCTX_INIT; 354198389Smav softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 355198389Smav SYSCTL_STATIC_CHILDREN(_kern_cam_pmp), OID_AUTO, tmpstr2, 356198389Smav CTLFLAG_RD, 0, tmpstr); 357198389Smav if (softc->sysctl_tree == NULL) { 358198389Smav printf("pmpsysctlinit: unable to allocate sysctl tree\n"); 359198389Smav cam_periph_release(periph); 360198389Smav return; 361198389Smav } 362198389Smav 363198389Smav cam_periph_release(periph); 364198389Smav} 365198389Smav 366198389Smavstatic cam_status 367198389Smavpmpregister(struct cam_periph *periph, void *arg) 368198389Smav{ 369198389Smav struct pmp_softc *softc; 370198389Smav struct ccb_getdev *cgd; 371198389Smav 372198389Smav cgd = (struct ccb_getdev *)arg; 373198389Smav if (cgd == NULL) { 374198389Smav printf("pmpregister: no getdev CCB, can't register device\n"); 375198389Smav return(CAM_REQ_CMP_ERR); 376198389Smav } 377198389Smav 378198389Smav softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF, 379198389Smav M_NOWAIT|M_ZERO); 380198389Smav 381198389Smav if (softc == NULL) { 382198389Smav printf("pmpregister: Unable to probe new device. " 383198389Smav "Unable to allocate softc\n"); 384198389Smav return(CAM_REQ_CMP_ERR); 385198389Smav } 386198389Smav periph->softc = softc; 387198389Smav 388198389Smav softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0]; 389198389Smav softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1]; 390198389Smav TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph); 391198389Smav 392198389Smav xpt_announce_periph(periph, NULL); 393198389Smav 394198389Smav /* 395198389Smav * Add async callbacks for bus reset and 396198389Smav * bus device reset calls. I don't bother 397198389Smav * checking if this fails as, in most cases, 398198389Smav * the system will function just fine without 399198389Smav * them and the only alternative would be to 400198389Smav * not attach the device on failure. 401198389Smav */ 402198389Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 403198389Smav AC_SCSI_AEN, pmpasync, periph, periph->path); 404198389Smav 405198389Smav /* 406198389Smav * Take an exclusive refcount on the periph while pmpstart is called 407198389Smav * to finish the probe. The reference will be dropped in pmpdone at 408198389Smav * the end of probe. 409198389Smav */ 410198389Smav (void)cam_periph_acquire(periph); 411203108Smav xpt_hold_boot(); 412203108Smav softc->state = PMP_STATE_PORTS; 413203108Smav softc->events = PMP_EV_RESCAN; 414203108Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 415198389Smav 416198389Smav return(CAM_REQ_CMP); 417198389Smav} 418198389Smav 419198389Smavstatic void 420198389Smavpmpstart(struct cam_periph *periph, union ccb *start_ccb) 421198389Smav{ 422203108Smav struct ccb_trans_settings cts; 423198389Smav struct ccb_ataio *ataio; 424198389Smav struct pmp_softc *softc; 425203108Smav struct cam_path *dpath; 426203108Smav int revision = 0; 427198389Smav 428198389Smav softc = (struct pmp_softc *)periph->softc; 429198389Smav ataio = &start_ccb->ataio; 430237305Smav 431237305Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpstart\n")); 432237305Smav 433198708Smav if (softc->restart) { 434198708Smav softc->restart = 0; 435251096Smav if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095) 436251096Smav softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1); 437251096Smav else 438251096Smav softc->state = min(softc->state, PMP_STATE_PRECONFIG); 439198708Smav } 440203108Smav /* Fetch user wanted device speed. */ 441203108Smav if (softc->state == PMP_STATE_RESET || 442203108Smav softc->state == PMP_STATE_CONNECT) { 443203108Smav if (xpt_create_path(&dpath, periph, 444203108Smav xpt_path_path_id(periph->path), 445203108Smav softc->pm_step, 0) == CAM_REQ_CMP) { 446203108Smav bzero(&cts, sizeof(cts)); 447203108Smav xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 448203108Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 449203108Smav cts.type = CTS_TYPE_USER_SETTINGS; 450203108Smav xpt_action((union ccb *)&cts); 451203108Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_REVISION) 452203108Smav revision = cts.xport_specific.sata.revision; 453203108Smav xpt_free_path(dpath); 454203108Smav } 455203108Smav } 456198389Smav switch (softc->state) { 457198389Smav case PMP_STATE_PORTS: 458198389Smav cam_fill_ataio(ataio, 459198389Smav pmp_retry_count, 460198389Smav pmpdone, 461198389Smav /*flags*/CAM_DIR_NONE, 462198389Smav 0, 463198389Smav /*data_ptr*/NULL, 464198389Smav /*dxfer_len*/0, 465198389Smav pmp_default_timeout * 1000); 466198389Smav ata_pm_read_cmd(ataio, 2, 15); 467198389Smav break; 468251096Smav 469251096Smav case PMP_STATE_PM_QUIRKS_1: 470251096Smav case PMP_STATE_PM_QUIRKS_3: 471251096Smav cam_fill_ataio(ataio, 472251096Smav pmp_retry_count, 473251096Smav pmpdone, 474251096Smav /*flags*/CAM_DIR_NONE, 475251096Smav 0, 476251096Smav /*data_ptr*/NULL, 477251096Smav /*dxfer_len*/0, 478251096Smav pmp_default_timeout * 1000); 479251096Smav ata_pm_read_cmd(ataio, 129, 15); 480251096Smav break; 481251096Smav 482251096Smav case PMP_STATE_PM_QUIRKS_2: 483251096Smav cam_fill_ataio(ataio, 484251096Smav pmp_retry_count, 485251096Smav pmpdone, 486251096Smav /*flags*/CAM_DIR_NONE, 487251096Smav 0, 488251096Smav /*data_ptr*/NULL, 489251096Smav /*dxfer_len*/0, 490251096Smav pmp_default_timeout * 1000); 491251096Smav ata_pm_write_cmd(ataio, 129, 15, softc->caps & ~0x1); 492251096Smav break; 493251096Smav 494199321Smav case PMP_STATE_PRECONFIG: 495207499Smav /* Get/update host SATA capabilities. */ 496207499Smav bzero(&cts, sizeof(cts)); 497207499Smav xpt_setup_ccb(&cts.ccb_h, periph->path, CAM_PRIORITY_NONE); 498207499Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 499207499Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 500207499Smav xpt_action((union ccb *)&cts); 501207499Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_CAPS) 502207499Smav softc->caps = cts.xport_specific.sata.caps; 503251096Smav else 504251096Smav softc->caps = 0; 505198389Smav cam_fill_ataio(ataio, 506198389Smav pmp_retry_count, 507198389Smav pmpdone, 508198389Smav /*flags*/CAM_DIR_NONE, 509198389Smav 0, 510198389Smav /*data_ptr*/NULL, 511198389Smav /*dxfer_len*/0, 512198389Smav pmp_default_timeout * 1000); 513199321Smav ata_pm_write_cmd(ataio, 0x60, 15, 0x0); 514198389Smav break; 515198389Smav case PMP_STATE_RESET: 516198389Smav cam_fill_ataio(ataio, 517198389Smav pmp_retry_count, 518198389Smav pmpdone, 519198389Smav /*flags*/CAM_DIR_NONE, 520198389Smav 0, 521198389Smav /*data_ptr*/NULL, 522198389Smav /*dxfer_len*/0, 523198389Smav pmp_default_timeout * 1000); 524198389Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 525203108Smav (revision << 4) | 526203108Smav ((softc->found & (1 << softc->pm_step)) ? 0 : 1)); 527198389Smav break; 528198389Smav case PMP_STATE_CONNECT: 529198389Smav cam_fill_ataio(ataio, 530198389Smav pmp_retry_count, 531198389Smav pmpdone, 532198389Smav /*flags*/CAM_DIR_NONE, 533198389Smav 0, 534198389Smav /*data_ptr*/NULL, 535198389Smav /*dxfer_len*/0, 536198389Smav pmp_default_timeout * 1000); 537203108Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 538203108Smav (revision << 4)); 539198389Smav break; 540198389Smav case PMP_STATE_CHECK: 541198389Smav cam_fill_ataio(ataio, 542198389Smav pmp_retry_count, 543198389Smav pmpdone, 544198389Smav /*flags*/CAM_DIR_NONE, 545198389Smav 0, 546198389Smav /*data_ptr*/NULL, 547198389Smav /*dxfer_len*/0, 548198389Smav pmp_default_timeout * 1000); 549198389Smav ata_pm_read_cmd(ataio, 0, softc->pm_step); 550198389Smav break; 551198389Smav case PMP_STATE_CLEAR: 552198708Smav softc->reset = 0; 553198389Smav cam_fill_ataio(ataio, 554198389Smav pmp_retry_count, 555198389Smav pmpdone, 556198389Smav /*flags*/CAM_DIR_NONE, 557198389Smav 0, 558198389Smav /*data_ptr*/NULL, 559198389Smav /*dxfer_len*/0, 560198389Smav pmp_default_timeout * 1000); 561198389Smav ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF); 562198389Smav break; 563199321Smav case PMP_STATE_CONFIG: 564199321Smav cam_fill_ataio(ataio, 565199321Smav pmp_retry_count, 566199321Smav pmpdone, 567199321Smav /*flags*/CAM_DIR_NONE, 568199321Smav 0, 569199321Smav /*data_ptr*/NULL, 570199321Smav /*dxfer_len*/0, 571199321Smav pmp_default_timeout * 1000); 572220602Smav ata_pm_write_cmd(ataio, 0x60, 15, 0x07 | 573220602Smav ((softc->caps & CTS_SATA_CAPS_H_AN) ? 0x08 : 0)); 574199321Smav break; 575198389Smav default: 576198389Smav break; 577198389Smav } 578198389Smav xpt_action(start_ccb); 579198389Smav} 580198389Smav 581198389Smavstatic void 582198389Smavpmpdone(struct cam_periph *periph, union ccb *done_ccb) 583198389Smav{ 584199747Smav struct ccb_trans_settings cts; 585198389Smav struct pmp_softc *softc; 586198389Smav struct ccb_ataio *ataio; 587220778Smav struct cam_path *dpath; 588198708Smav u_int32_t priority, res; 589203108Smav int i; 590198389Smav 591198389Smav softc = (struct pmp_softc *)periph->softc; 592198389Smav ataio = &done_ccb->ataio; 593198389Smav 594237305Smav CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("pmpdone\n")); 595198389Smav 596198389Smav priority = done_ccb->ccb_h.pinfo.priority; 597198389Smav 598198708Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 599203385Smav if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) { 600198389Smav return; 601198389Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 602198708Smav cam_release_devq(done_ccb->ccb_h.path, 603198708Smav /*relsim_flags*/0, 604198708Smav /*reduction*/0, 605198708Smav /*timeout*/0, 606198708Smav /*getcount_only*/0); 607198389Smav } 608198708Smav goto done; 609198708Smav } 610198708Smav 611198708Smav if (softc->restart) { 612198708Smav softc->restart = 0; 613198389Smav xpt_release_ccb(done_ccb); 614251096Smav if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095) 615251096Smav softc->state = min(softc->state, PMP_STATE_PM_QUIRKS_1); 616251096Smav else 617251096Smav softc->state = min(softc->state, PMP_STATE_PRECONFIG); 618198708Smav xpt_schedule(periph, priority); 619198708Smav return; 620198708Smav } 621198708Smav 622198708Smav switch (softc->state) { 623198708Smav case PMP_STATE_PORTS: 624220778Smav softc->pm_ports = (ataio->res.lba_high << 24) + 625220778Smav (ataio->res.lba_mid << 16) + 626220778Smav (ataio->res.lba_low << 8) + 627220778Smav ataio->res.sector_count; 628236765Smav if (pmp_hide_special) { 629236765Smav /* 630236765Smav * This PMP declares 6 ports, while only 5 of them 631236765Smav * are real. Port 5 is a SEMB port, probing which 632236765Smav * causes timeouts if external SEP is not connected 633236765Smav * to PMP over I2C. 634236765Smav */ 635249160Smav if ((softc->pm_pid == 0x37261095 || 636249160Smav softc->pm_pid == 0x38261095) && 637249160Smav softc->pm_ports == 6) 638236765Smav softc->pm_ports = 5; 639236765Smav 640236765Smav /* 641236765Smav * This PMP declares 7 ports, while only 5 of them 642236765Smav * are real. Port 5 is a fake "Config Disk" with 643236765Smav * 640 sectors size. Port 6 is a SEMB port. 644236765Smav */ 645236765Smav if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) 646236765Smav softc->pm_ports = 5; 647236765Smav 648236765Smav /* 649236765Smav * These PMPs have extra configuration port. 650236765Smav */ 651236765Smav if (softc->pm_pid == 0x57231095 || 652236765Smav softc->pm_pid == 0x57331095 || 653236765Smav softc->pm_pid == 0x57341095 || 654236765Smav softc->pm_pid == 0x57441095) 655236765Smav softc->pm_ports--; 656236765Smav } 657200218Smav printf("%s%d: %d fan-out ports\n", 658200218Smav periph->periph_name, periph->unit_number, 659200218Smav softc->pm_ports); 660251096Smav if (softc->pm_pid == 0x37261095 || softc->pm_pid == 0x38261095) 661251096Smav softc->state = PMP_STATE_PM_QUIRKS_1; 662251096Smav else 663251096Smav softc->state = PMP_STATE_PRECONFIG; 664251096Smav xpt_release_ccb(done_ccb); 665251096Smav xpt_schedule(periph, priority); 666251096Smav return; 667251096Smav 668251096Smav case PMP_STATE_PM_QUIRKS_1: 669251096Smav softc->caps = (ataio->res.lba_high << 24) + 670251096Smav (ataio->res.lba_mid << 16) + 671251096Smav (ataio->res.lba_low << 8) + 672251096Smav ataio->res.sector_count; 673251096Smav if (softc->caps & 0x1) 674251096Smav softc->state = PMP_STATE_PM_QUIRKS_2; 675251096Smav else 676251096Smav softc->state = PMP_STATE_PRECONFIG; 677251096Smav xpt_release_ccb(done_ccb); 678251096Smav xpt_schedule(periph, priority); 679251096Smav return; 680251096Smav 681251096Smav case PMP_STATE_PM_QUIRKS_2: 682251096Smav if (bootverbose) 683251096Smav softc->state = PMP_STATE_PM_QUIRKS_3; 684251096Smav else 685251096Smav softc->state = PMP_STATE_PRECONFIG; 686251096Smav xpt_release_ccb(done_ccb); 687251096Smav xpt_schedule(periph, priority); 688251096Smav return; 689251096Smav 690251096Smav case PMP_STATE_PM_QUIRKS_3: 691251096Smav res = (ataio->res.lba_high << 24) + 692251096Smav (ataio->res.lba_mid << 16) + 693251096Smav (ataio->res.lba_low << 8) + 694251096Smav ataio->res.sector_count; 695251096Smav printf("%s%d: Disabling SiI3x26 R_OK in GSCR_POLL: %x->%x\n", 696251096Smav periph->periph_name, periph->unit_number, softc->caps, res); 697199321Smav softc->state = PMP_STATE_PRECONFIG; 698198708Smav xpt_release_ccb(done_ccb); 699198708Smav xpt_schedule(periph, priority); 700198708Smav return; 701251096Smav 702199321Smav case PMP_STATE_PRECONFIG: 703198708Smav softc->pm_step = 0; 704198708Smav softc->state = PMP_STATE_RESET; 705198708Smav softc->reset |= ~softc->found; 706198389Smav xpt_release_ccb(done_ccb); 707198708Smav xpt_schedule(periph, priority); 708198708Smav return; 709198389Smav case PMP_STATE_RESET: 710198708Smav softc->pm_step++; 711198708Smav if (softc->pm_step >= softc->pm_ports) { 712198708Smav softc->pm_step = 0; 713198708Smav cam_freeze_devq(periph->path); 714198708Smav cam_release_devq(periph->path, 715198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 716198708Smav /*reduction*/0, 717198708Smav /*timeout*/5, 718198708Smav /*getcount_only*/0); 719198708Smav softc->state = PMP_STATE_CONNECT; 720198389Smav } 721198389Smav xpt_release_ccb(done_ccb); 722198708Smav xpt_schedule(periph, priority); 723198708Smav return; 724198389Smav case PMP_STATE_CONNECT: 725198708Smav softc->pm_step++; 726198708Smav if (softc->pm_step >= softc->pm_ports) { 727198708Smav softc->pm_step = 0; 728198708Smav softc->pm_try = 0; 729198708Smav cam_freeze_devq(periph->path); 730198708Smav cam_release_devq(periph->path, 731198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 732198708Smav /*reduction*/0, 733198708Smav /*timeout*/10, 734198708Smav /*getcount_only*/0); 735198708Smav softc->state = PMP_STATE_CHECK; 736198389Smav } 737198389Smav xpt_release_ccb(done_ccb); 738198708Smav xpt_schedule(periph, priority); 739198708Smav return; 740198389Smav case PMP_STATE_CHECK: 741220778Smav res = (ataio->res.lba_high << 24) + 742220778Smav (ataio->res.lba_mid << 16) + 743220778Smav (ataio->res.lba_low << 8) + 744220778Smav ataio->res.sector_count; 745207499Smav if (((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) || 746207499Smav (res & 0x600) != 0) { 747200218Smav if (bootverbose) { 748200218Smav printf("%s%d: port %d status: %08x\n", 749200218Smav periph->periph_name, periph->unit_number, 750200218Smav softc->pm_step, res); 751200218Smav } 752207499Smav /* Report device speed if it is online. */ 753207499Smav if ((res & 0xf0f) == 0x103 && 754207499Smav xpt_create_path(&dpath, periph, 755199747Smav xpt_path_path_id(periph->path), 756199747Smav softc->pm_step, 0) == CAM_REQ_CMP) { 757199747Smav bzero(&cts, sizeof(cts)); 758203108Smav xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 759199747Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 760199747Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 761199747Smav cts.xport_specific.sata.revision = (res & 0x0f0) >> 4; 762199747Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION; 763207499Smav cts.xport_specific.sata.caps = softc->caps & 764220602Smav (CTS_SATA_CAPS_H_PMREQ | 765220602Smav CTS_SATA_CAPS_H_DMAAA | 766220602Smav CTS_SATA_CAPS_H_AN); 767207499Smav cts.xport_specific.sata.valid |= CTS_SATA_VALID_CAPS; 768199747Smav xpt_action((union ccb *)&cts); 769199747Smav xpt_free_path(dpath); 770199747Smav } 771198708Smav softc->found |= (1 << softc->pm_step); 772198708Smav softc->pm_step++; 773198708Smav } else { 774198708Smav if (softc->pm_try < 10) { 775198708Smav cam_freeze_devq(periph->path); 776198708Smav cam_release_devq(periph->path, 777198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 778198708Smav /*reduction*/0, 779198708Smav /*timeout*/10, 780198708Smav /*getcount_only*/0); 781198708Smav softc->pm_try++; 782198708Smav } else { 783200218Smav if (bootverbose) { 784200218Smav printf("%s%d: port %d status: %08x\n", 785200218Smav periph->periph_name, periph->unit_number, 786200218Smav softc->pm_step, res); 787200218Smav } 788198708Smav softc->found &= ~(1 << softc->pm_step); 789198708Smav if (xpt_create_path(&dpath, periph, 790198708Smav done_ccb->ccb_h.path_id, 791198708Smav softc->pm_step, 0) == CAM_REQ_CMP) { 792198708Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 793198708Smav xpt_free_path(dpath); 794198708Smav } 795198389Smav softc->pm_step++; 796198389Smav } 797198708Smav } 798198708Smav if (softc->pm_step >= softc->pm_ports) { 799198708Smav if (softc->reset & softc->found) { 800198708Smav cam_freeze_devq(periph->path); 801198708Smav cam_release_devq(periph->path, 802198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 803198708Smav /*reduction*/0, 804198708Smav /*timeout*/1000, 805198708Smav /*getcount_only*/0); 806198389Smav } 807198708Smav softc->state = PMP_STATE_CLEAR; 808198708Smav softc->pm_step = 0; 809198389Smav } 810198389Smav xpt_release_ccb(done_ccb); 811198708Smav xpt_schedule(periph, priority); 812198708Smav return; 813198389Smav case PMP_STATE_CLEAR: 814198708Smav softc->pm_step++; 815199321Smav if (softc->pm_step >= softc->pm_ports) { 816199321Smav softc->state = PMP_STATE_CONFIG; 817198708Smav softc->pm_step = 0; 818199321Smav } 819199321Smav xpt_release_ccb(done_ccb); 820199321Smav xpt_schedule(periph, priority); 821199321Smav return; 822199321Smav case PMP_STATE_CONFIG: 823203108Smav for (i = 0; i < softc->pm_ports; i++) { 824203108Smav union ccb *ccb; 825203108Smav 826203108Smav if ((softc->found & (1 << i)) == 0) 827203108Smav continue; 828203108Smav if (xpt_create_path(&dpath, periph, 829203108Smav xpt_path_path_id(periph->path), 830203108Smav i, 0) != CAM_REQ_CMP) { 831208819Smav printf("pmpdone: xpt_create_path failed\n"); 832208819Smav continue; 833203108Smav } 834203108Smav /* If we did hard reset to this device, inform XPT. */ 835203108Smav if ((softc->reset & softc->found & (1 << i)) != 0) 836203108Smav xpt_async(AC_SENT_BDR, dpath, NULL); 837203108Smav /* If rescan requested, scan this device. */ 838203108Smav if (softc->events & PMP_EV_RESCAN) { 839203108Smav ccb = xpt_alloc_ccb_nowait(); 840203108Smav if (ccb == NULL) { 841203108Smav xpt_free_path(dpath); 842203108Smav goto done; 843203108Smav } 844203108Smav xpt_setup_ccb(&ccb->ccb_h, dpath, CAM_PRIORITY_XPT); 845203108Smav xpt_rescan(ccb); 846203108Smav } else 847203108Smav xpt_free_path(dpath); 848198389Smav } 849198389Smav break; 850198389Smav default: 851198389Smav break; 852198389Smav } 853198708Smavdone: 854198708Smav xpt_release_ccb(done_ccb); 855198389Smav softc->state = PMP_STATE_NORMAL; 856203108Smav softc->events = 0; 857203108Smav xpt_release_boot(); 858198389Smav pmprelease(periph, -1); 859198389Smav cam_periph_release_locked(periph); 860198389Smav} 861198389Smav 862198389Smav#endif /* _KERNEL */ 863