ata_pmp.c revision 203385
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: head/sys/cam/ata/ata_pmp.c 203385 2010-02-02 18:03:21Z 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, 67199321Smav PMP_STATE_PRECONFIG, 68198389Smav PMP_STATE_RESET, 69198389Smav PMP_STATE_CONNECT, 70198389Smav PMP_STATE_CHECK, 71198389Smav PMP_STATE_CLEAR, 72199321Smav PMP_STATE_CONFIG, 73198389Smav PMP_STATE_SCAN 74198389Smav} pmp_state; 75198389Smav 76198389Smavtypedef enum { 77198389Smav PMP_FLAG_SCTX_INIT = 0x200 78198389Smav} pmp_flags; 79198389Smav 80198389Smavtypedef enum { 81198389Smav PMP_CCB_PROBE = 0x01, 82198389Smav} pmp_ccb_state; 83198389Smav 84198389Smav/* Offsets into our private area for storing information */ 85198389Smav#define ccb_state ppriv_field0 86198389Smav#define ccb_bp ppriv_ptr1 87198389Smav 88198389Smavstruct pmp_softc { 89198389Smav SLIST_ENTRY(pmp_softc) links; 90198389Smav pmp_state state; 91198389Smav pmp_flags flags; 92198389Smav uint32_t pm_pid; 93198389Smav uint32_t pm_prv; 94198389Smav int pm_ports; 95198389Smav int pm_step; 96198389Smav int pm_try; 97198389Smav int found; 98198708Smav int reset; 99198389Smav int frozen; 100198708Smav int restart; 101203108Smav int events; 102203108Smav#define PMP_EV_RESET 1 103203108Smav#define PMP_EV_RESCAN 2 104198389Smav struct task sysctl_task; 105198389Smav struct sysctl_ctx_list sysctl_ctx; 106198389Smav struct sysctl_oid *sysctl_tree; 107198389Smav}; 108198389Smav 109198389Smavstatic periph_init_t pmpinit; 110198389Smavstatic void pmpasync(void *callback_arg, u_int32_t code, 111198389Smav struct cam_path *path, void *arg); 112198389Smavstatic void pmpsysctlinit(void *context, int pending); 113198389Smavstatic periph_ctor_t pmpregister; 114198389Smavstatic periph_dtor_t pmpcleanup; 115198389Smavstatic periph_start_t pmpstart; 116198389Smavstatic periph_oninv_t pmponinvalidate; 117198389Smavstatic void pmpdone(struct cam_periph *periph, 118198389Smav union ccb *done_ccb); 119198389Smav 120198389Smav#ifndef PMP_DEFAULT_TIMEOUT 121198389Smav#define PMP_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 122198389Smav#endif 123198389Smav 124198389Smav#ifndef PMP_DEFAULT_RETRY 125198389Smav#define PMP_DEFAULT_RETRY 1 126198389Smav#endif 127198389Smav 128198389Smavstatic int pmp_retry_count = PMP_DEFAULT_RETRY; 129198389Smavstatic int pmp_default_timeout = PMP_DEFAULT_TIMEOUT; 130198389Smav 131198389SmavSYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD, 0, 132198389Smav "CAM Direct Access Disk driver"); 133198389SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RW, 134198389Smav &pmp_retry_count, 0, "Normal I/O retry count"); 135198389SmavTUNABLE_INT("kern.cam.pmp.retry_count", &pmp_retry_count); 136198389SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RW, 137198389Smav &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)"); 138198389SmavTUNABLE_INT("kern.cam.pmp.default_timeout", &pmp_default_timeout); 139198389Smav 140198389Smavstatic struct periph_driver pmpdriver = 141198389Smav{ 142198389Smav pmpinit, "pmp", 143198708Smav TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0, 144198708Smav CAM_PERIPH_DRV_EARLY 145198389Smav}; 146198389Smav 147198389SmavPERIPHDRIVER_DECLARE(pmp, pmpdriver); 148198389Smav 149198389SmavMALLOC_DEFINE(M_ATPMP, "ata_pmp", "ata_pmp buffers"); 150198389Smav 151198389Smavstatic void 152198389Smavpmpinit(void) 153198389Smav{ 154198389Smav cam_status status; 155198389Smav 156198389Smav /* 157198389Smav * Install a global async callback. This callback will 158198389Smav * receive async callbacks like "new device found". 159198389Smav */ 160198389Smav status = xpt_register_async(AC_FOUND_DEVICE, pmpasync, NULL, NULL); 161198389Smav 162198389Smav if (status != CAM_REQ_CMP) { 163198389Smav printf("pmp: Failed to attach master async callback " 164198389Smav "due to status 0x%x!\n", status); 165198389Smav } 166198389Smav} 167198389Smav 168198389Smavstatic void 169198389Smavpmpfreeze(struct cam_periph *periph, int mask) 170198389Smav{ 171198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 172198389Smav struct cam_path *dpath; 173198389Smav int i; 174198389Smav 175198389Smav mask &= ~softc->frozen; 176198389Smav for (i = 0; i < 15; i++) { 177198389Smav if ((mask & (1 << i)) == 0) 178198389Smav continue; 179198389Smav if (xpt_create_path(&dpath, periph, 180198389Smav xpt_path_path_id(periph->path), 181198389Smav i, 0) == CAM_REQ_CMP) { 182198389Smav softc->frozen |= (1 << i); 183200218Smav xpt_acquire_device(dpath->device); 184203108Smav cam_freeze_devq_arg(dpath, 185203108Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_BUS + 1); 186198389Smav xpt_free_path(dpath); 187198389Smav } 188198389Smav } 189198389Smav} 190198389Smav 191198389Smavstatic void 192198389Smavpmprelease(struct cam_periph *periph, int mask) 193198389Smav{ 194198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 195198389Smav struct cam_path *dpath; 196198389Smav int i; 197198389Smav 198198389Smav mask &= softc->frozen; 199198389Smav for (i = 0; i < 15; i++) { 200198389Smav if ((mask & (1 << i)) == 0) 201198389Smav continue; 202198389Smav if (xpt_create_path(&dpath, periph, 203198389Smav xpt_path_path_id(periph->path), 204198389Smav i, 0) == CAM_REQ_CMP) { 205198389Smav softc->frozen &= ~(1 << i); 206203108Smav cam_release_devq(dpath, 207203108Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_BUS + 1, FALSE); 208200218Smav xpt_release_device(dpath->device); 209198389Smav xpt_free_path(dpath); 210198389Smav } 211198389Smav } 212198389Smav} 213198389Smav 214198389Smavstatic void 215198389Smavpmponinvalidate(struct cam_periph *periph) 216198389Smav{ 217198389Smav struct pmp_softc *softc; 218198389Smav struct cam_path *dpath; 219198389Smav int i; 220198389Smav 221198389Smav softc = (struct pmp_softc *)periph->softc; 222198389Smav 223198389Smav /* 224198389Smav * De-register any async callbacks. 225198389Smav */ 226198389Smav xpt_register_async(0, pmpasync, periph, periph->path); 227198389Smav 228198389Smav for (i = 0; i < 15; i++) { 229198389Smav if (xpt_create_path(&dpath, periph, 230198389Smav xpt_path_path_id(periph->path), 231198389Smav i, 0) == CAM_REQ_CMP) { 232198389Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 233198389Smav xpt_free_path(dpath); 234198389Smav } 235198389Smav } 236200218Smav pmprelease(periph, -1); 237198389Smav xpt_print(periph->path, "lost device\n"); 238198389Smav} 239198389Smav 240198389Smavstatic void 241198389Smavpmpcleanup(struct cam_periph *periph) 242198389Smav{ 243198389Smav struct pmp_softc *softc; 244198389Smav 245198389Smav softc = (struct pmp_softc *)periph->softc; 246198389Smav 247198389Smav xpt_print(periph->path, "removing device entry\n"); 248198389Smav cam_periph_unlock(periph); 249198389Smav 250198389Smav /* 251198389Smav * If we can't free the sysctl tree, oh well... 252198389Smav */ 253198389Smav if ((softc->flags & PMP_FLAG_SCTX_INIT) != 0 254198389Smav && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 255198389Smav xpt_print(periph->path, "can't remove sysctl context\n"); 256198389Smav } 257198389Smav 258198389Smav free(softc, M_DEVBUF); 259198389Smav cam_periph_lock(periph); 260198389Smav} 261198389Smav 262198389Smavstatic void 263198389Smavpmpasync(void *callback_arg, u_int32_t code, 264198389Smav struct cam_path *path, void *arg) 265198389Smav{ 266198389Smav struct cam_periph *periph; 267198389Smav struct pmp_softc *softc; 268198389Smav 269198389Smav periph = (struct cam_periph *)callback_arg; 270198389Smav switch (code) { 271198389Smav case AC_FOUND_DEVICE: 272198389Smav { 273198389Smav struct ccb_getdev *cgd; 274198389Smav cam_status status; 275198389Smav 276198389Smav cgd = (struct ccb_getdev *)arg; 277198389Smav if (cgd == NULL) 278198389Smav break; 279198389Smav 280198389Smav if (cgd->protocol != PROTO_SATAPM) 281198389Smav break; 282198389Smav 283198389Smav /* 284198389Smav * Allocate a peripheral instance for 285198389Smav * this device and start the probe 286198389Smav * process. 287198389Smav */ 288198389Smav status = cam_periph_alloc(pmpregister, pmponinvalidate, 289198389Smav pmpcleanup, pmpstart, 290198389Smav "pmp", CAM_PERIPH_BIO, 291198389Smav cgd->ccb_h.path, pmpasync, 292198389Smav AC_FOUND_DEVICE, cgd); 293198389Smav 294198389Smav if (status != CAM_REQ_CMP 295198389Smav && status != CAM_REQ_INPROG) 296198389Smav printf("pmpasync: Unable to attach to new device " 297198389Smav "due to status 0x%x\n", status); 298198389Smav break; 299198389Smav } 300198389Smav case AC_SCSI_AEN: 301198389Smav case AC_SENT_BDR: 302198389Smav case AC_BUS_RESET: 303198389Smav softc = (struct pmp_softc *)periph->softc; 304198389Smav cam_periph_async(periph, code, path, arg); 305203108Smav if (code == AC_SCSI_AEN) 306203108Smav softc->events |= PMP_EV_RESCAN; 307203108Smav else 308203108Smav softc->events |= PMP_EV_RESET; 309203108Smav if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL) 310198389Smav break; 311203108Smav xpt_hold_boot(); 312203108Smav pmpfreeze(periph, softc->found); 313198389Smav if (code == AC_SENT_BDR || code == AC_BUS_RESET) 314198389Smav softc->found = 0; /* We have to reset everything. */ 315198708Smav if (softc->state == PMP_STATE_NORMAL) { 316203108Smav softc->state = PMP_STATE_PRECONFIG; 317198708Smav cam_periph_acquire(periph); 318203108Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 319198708Smav } else 320198708Smav softc->restart = 1; 321198389Smav break; 322198389Smav default: 323198389Smav cam_periph_async(periph, code, path, arg); 324198389Smav break; 325198389Smav } 326198389Smav} 327198389Smav 328198389Smavstatic void 329198389Smavpmpsysctlinit(void *context, int pending) 330198389Smav{ 331198389Smav struct cam_periph *periph; 332198389Smav struct pmp_softc *softc; 333198389Smav char tmpstr[80], tmpstr2[80]; 334198389Smav 335198389Smav periph = (struct cam_periph *)context; 336198389Smav if (cam_periph_acquire(periph) != CAM_REQ_CMP) 337198389Smav return; 338198389Smav 339198389Smav softc = (struct pmp_softc *)periph->softc; 340198389Smav snprintf(tmpstr, sizeof(tmpstr), "CAM PMP unit %d", periph->unit_number); 341198389Smav snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 342198389Smav 343198389Smav sysctl_ctx_init(&softc->sysctl_ctx); 344198389Smav softc->flags |= PMP_FLAG_SCTX_INIT; 345198389Smav softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 346198389Smav SYSCTL_STATIC_CHILDREN(_kern_cam_pmp), OID_AUTO, tmpstr2, 347198389Smav CTLFLAG_RD, 0, tmpstr); 348198389Smav if (softc->sysctl_tree == NULL) { 349198389Smav printf("pmpsysctlinit: unable to allocate sysctl tree\n"); 350198389Smav cam_periph_release(periph); 351198389Smav return; 352198389Smav } 353198389Smav 354198389Smav cam_periph_release(periph); 355198389Smav} 356198389Smav 357198389Smavstatic cam_status 358198389Smavpmpregister(struct cam_periph *periph, void *arg) 359198389Smav{ 360198389Smav struct pmp_softc *softc; 361198389Smav struct ccb_getdev *cgd; 362198389Smav 363198389Smav cgd = (struct ccb_getdev *)arg; 364198389Smav if (periph == NULL) { 365198389Smav printf("pmpregister: periph was NULL!!\n"); 366198389Smav return(CAM_REQ_CMP_ERR); 367198389Smav } 368198389Smav 369198389Smav if (cgd == NULL) { 370198389Smav printf("pmpregister: no getdev CCB, can't register device\n"); 371198389Smav return(CAM_REQ_CMP_ERR); 372198389Smav } 373198389Smav 374198389Smav softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF, 375198389Smav M_NOWAIT|M_ZERO); 376198389Smav 377198389Smav if (softc == NULL) { 378198389Smav printf("pmpregister: Unable to probe new device. " 379198389Smav "Unable to allocate softc\n"); 380198389Smav return(CAM_REQ_CMP_ERR); 381198389Smav } 382198389Smav periph->softc = softc; 383198389Smav 384198389Smav softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0]; 385198389Smav softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1]; 386198389Smav TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph); 387198389Smav 388198389Smav xpt_announce_periph(periph, NULL); 389198389Smav 390198389Smav /* 391198389Smav * Add async callbacks for bus reset and 392198389Smav * bus device reset calls. I don't bother 393198389Smav * checking if this fails as, in most cases, 394198389Smav * the system will function just fine without 395198389Smav * them and the only alternative would be to 396198389Smav * not attach the device on failure. 397198389Smav */ 398198389Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 399198389Smav AC_SCSI_AEN, pmpasync, periph, periph->path); 400198389Smav 401198389Smav /* 402198389Smav * Take an exclusive refcount on the periph while pmpstart is called 403198389Smav * to finish the probe. The reference will be dropped in pmpdone at 404198389Smav * the end of probe. 405198389Smav */ 406198389Smav (void)cam_periph_acquire(periph); 407203108Smav xpt_hold_boot(); 408203108Smav softc->state = PMP_STATE_PORTS; 409203108Smav softc->events = PMP_EV_RESCAN; 410203108Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 411198389Smav 412198389Smav return(CAM_REQ_CMP); 413198389Smav} 414198389Smav 415198389Smavstatic void 416198389Smavpmpstart(struct cam_periph *periph, union ccb *start_ccb) 417198389Smav{ 418203108Smav struct ccb_trans_settings cts; 419198389Smav struct ccb_ataio *ataio; 420198389Smav struct pmp_softc *softc; 421203108Smav struct cam_path *dpath; 422203108Smav int revision = 0; 423198389Smav 424198389Smav softc = (struct pmp_softc *)periph->softc; 425198389Smav ataio = &start_ccb->ataio; 426198708Smav 427198708Smav if (softc->restart) { 428198708Smav softc->restart = 0; 429203108Smav softc->state = min(softc->state, PMP_STATE_PRECONFIG); 430198708Smav } 431203108Smav /* Fetch user wanted device speed. */ 432203108Smav if (softc->state == PMP_STATE_RESET || 433203108Smav softc->state == PMP_STATE_CONNECT) { 434203108Smav if (xpt_create_path(&dpath, periph, 435203108Smav xpt_path_path_id(periph->path), 436203108Smav softc->pm_step, 0) == CAM_REQ_CMP) { 437203108Smav bzero(&cts, sizeof(cts)); 438203108Smav xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 439203108Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 440203108Smav cts.type = CTS_TYPE_USER_SETTINGS; 441203108Smav xpt_action((union ccb *)&cts); 442203108Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_REVISION) 443203108Smav revision = cts.xport_specific.sata.revision; 444203108Smav xpt_free_path(dpath); 445203108Smav } 446203108Smav } 447198389Smav switch (softc->state) { 448198389Smav case PMP_STATE_PORTS: 449198389Smav cam_fill_ataio(ataio, 450198389Smav pmp_retry_count, 451198389Smav pmpdone, 452198389Smav /*flags*/CAM_DIR_NONE, 453198389Smav 0, 454198389Smav /*data_ptr*/NULL, 455198389Smav /*dxfer_len*/0, 456198389Smav pmp_default_timeout * 1000); 457198389Smav ata_pm_read_cmd(ataio, 2, 15); 458198389Smav break; 459199321Smav case PMP_STATE_PRECONFIG: 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); 468199321Smav ata_pm_write_cmd(ataio, 0x60, 15, 0x0); 469198389Smav break; 470198389Smav case PMP_STATE_RESET: 471198389Smav cam_fill_ataio(ataio, 472198389Smav pmp_retry_count, 473198389Smav pmpdone, 474198389Smav /*flags*/CAM_DIR_NONE, 475198389Smav 0, 476198389Smav /*data_ptr*/NULL, 477198389Smav /*dxfer_len*/0, 478198389Smav pmp_default_timeout * 1000); 479198389Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 480203108Smav (revision << 4) | 481203108Smav ((softc->found & (1 << softc->pm_step)) ? 0 : 1)); 482198389Smav break; 483198389Smav case PMP_STATE_CONNECT: 484198389Smav cam_fill_ataio(ataio, 485198389Smav pmp_retry_count, 486198389Smav pmpdone, 487198389Smav /*flags*/CAM_DIR_NONE, 488198389Smav 0, 489198389Smav /*data_ptr*/NULL, 490198389Smav /*dxfer_len*/0, 491198389Smav pmp_default_timeout * 1000); 492203108Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 493203108Smav (revision << 4)); 494198389Smav break; 495198389Smav case PMP_STATE_CHECK: 496198389Smav cam_fill_ataio(ataio, 497198389Smav pmp_retry_count, 498198389Smav pmpdone, 499198389Smav /*flags*/CAM_DIR_NONE, 500198389Smav 0, 501198389Smav /*data_ptr*/NULL, 502198389Smav /*dxfer_len*/0, 503198389Smav pmp_default_timeout * 1000); 504198389Smav ata_pm_read_cmd(ataio, 0, softc->pm_step); 505198389Smav break; 506198389Smav case PMP_STATE_CLEAR: 507198708Smav softc->reset = 0; 508198389Smav cam_fill_ataio(ataio, 509198389Smav pmp_retry_count, 510198389Smav pmpdone, 511198389Smav /*flags*/CAM_DIR_NONE, 512198389Smav 0, 513198389Smav /*data_ptr*/NULL, 514198389Smav /*dxfer_len*/0, 515198389Smav pmp_default_timeout * 1000); 516198389Smav ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF); 517198389Smav break; 518199321Smav case PMP_STATE_CONFIG: 519199321Smav cam_fill_ataio(ataio, 520199321Smav pmp_retry_count, 521199321Smav pmpdone, 522199321Smav /*flags*/CAM_DIR_NONE, 523199321Smav 0, 524199321Smav /*data_ptr*/NULL, 525199321Smav /*dxfer_len*/0, 526199321Smav pmp_default_timeout * 1000); 527199321Smav ata_pm_write_cmd(ataio, 0x60, 15, 0xf); 528199321Smav break; 529198389Smav default: 530198389Smav break; 531198389Smav } 532198389Smav xpt_action(start_ccb); 533198389Smav} 534198389Smav 535198389Smavstatic void 536198389Smavpmpdone(struct cam_periph *periph, union ccb *done_ccb) 537198389Smav{ 538199747Smav struct ccb_trans_settings cts; 539198389Smav struct pmp_softc *softc; 540198389Smav struct ccb_ataio *ataio; 541198389Smav struct cam_path *path, *dpath; 542198708Smav u_int32_t priority, res; 543203108Smav int i; 544198389Smav 545198389Smav softc = (struct pmp_softc *)periph->softc; 546198389Smav ataio = &done_ccb->ataio; 547198389Smav 548198389Smav CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("pmpdone\n")); 549198389Smav 550198389Smav path = done_ccb->ccb_h.path; 551198389Smav priority = done_ccb->ccb_h.pinfo.priority; 552198389Smav 553198708Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 554203385Smav if (cam_periph_error(done_ccb, 0, 0, NULL) == ERESTART) { 555198389Smav return; 556198389Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 557198708Smav cam_release_devq(done_ccb->ccb_h.path, 558198708Smav /*relsim_flags*/0, 559198708Smav /*reduction*/0, 560198708Smav /*timeout*/0, 561198708Smav /*getcount_only*/0); 562198389Smav } 563198708Smav goto done; 564198708Smav } 565198708Smav 566198708Smav if (softc->restart) { 567198708Smav softc->restart = 0; 568198389Smav xpt_release_ccb(done_ccb); 569203108Smav softc->state = min(softc->state, PMP_STATE_PRECONFIG); 570198708Smav xpt_schedule(periph, priority); 571198708Smav return; 572198708Smav } 573198708Smav 574198708Smav switch (softc->state) { 575198708Smav case PMP_STATE_PORTS: 576198708Smav softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) + 577198708Smav (done_ccb->ataio.res.lba_mid << 16) + 578198708Smav (done_ccb->ataio.res.lba_low << 8) + 579198708Smav done_ccb->ataio.res.sector_count; 580199321Smav /* This PMP declares 6 ports, while only 5 of them are real. 581198708Smav * Port 5 is enclosure management bridge port, which has implementation 582198708Smav * problems, causing probe faults. Hide it for now. */ 583198708Smav if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) 584198708Smav softc->pm_ports = 5; 585199321Smav /* This PMP declares 7 ports, while only 5 of them are real. 586198708Smav * Port 5 is some fake "Config Disk" with 640 sectors size, 587198708Smav * port 6 is enclosure management bridge port. 588198708Smav * Both fake ports has implementation problems, causing 589198708Smav * probe faults. Hide them for now. */ 590198708Smav if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) 591198708Smav softc->pm_ports = 5; 592199321Smav /* These PMPs declare one more port then actually have, 593199321Smav * for configuration purposes. Hide it for now. */ 594199321Smav if (softc->pm_pid == 0x57231095 || softc->pm_pid == 0x57331095 || 595199321Smav softc->pm_pid == 0x57341095 || softc->pm_pid == 0x57441095) 596199321Smav softc->pm_ports--; 597200218Smav printf("%s%d: %d fan-out ports\n", 598200218Smav periph->periph_name, periph->unit_number, 599200218Smav softc->pm_ports); 600199321Smav softc->state = PMP_STATE_PRECONFIG; 601198708Smav xpt_release_ccb(done_ccb); 602198708Smav xpt_schedule(periph, priority); 603198708Smav return; 604199321Smav case PMP_STATE_PRECONFIG: 605198708Smav softc->pm_step = 0; 606198708Smav softc->state = PMP_STATE_RESET; 607198708Smav softc->reset |= ~softc->found; 608198389Smav xpt_release_ccb(done_ccb); 609198708Smav xpt_schedule(periph, priority); 610198708Smav return; 611198389Smav case PMP_STATE_RESET: 612198708Smav softc->pm_step++; 613198708Smav if (softc->pm_step >= softc->pm_ports) { 614198708Smav softc->pm_step = 0; 615198708Smav cam_freeze_devq(periph->path); 616198708Smav cam_release_devq(periph->path, 617198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 618198708Smav /*reduction*/0, 619198708Smav /*timeout*/5, 620198708Smav /*getcount_only*/0); 621198708Smav softc->state = PMP_STATE_CONNECT; 622198389Smav } 623198389Smav xpt_release_ccb(done_ccb); 624198708Smav xpt_schedule(periph, priority); 625198708Smav return; 626198389Smav case PMP_STATE_CONNECT: 627198708Smav softc->pm_step++; 628198708Smav if (softc->pm_step >= softc->pm_ports) { 629198708Smav softc->pm_step = 0; 630198708Smav softc->pm_try = 0; 631198708Smav cam_freeze_devq(periph->path); 632198708Smav cam_release_devq(periph->path, 633198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 634198708Smav /*reduction*/0, 635198708Smav /*timeout*/10, 636198708Smav /*getcount_only*/0); 637198708Smav softc->state = PMP_STATE_CHECK; 638198389Smav } 639198389Smav xpt_release_ccb(done_ccb); 640198708Smav xpt_schedule(periph, priority); 641198708Smav return; 642198389Smav case PMP_STATE_CHECK: 643198708Smav res = (done_ccb->ataio.res.lba_high << 24) + 644198708Smav (done_ccb->ataio.res.lba_mid << 16) + 645198708Smav (done_ccb->ataio.res.lba_low << 8) + 646198708Smav done_ccb->ataio.res.sector_count; 647198708Smav if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) { 648200218Smav if (bootverbose) { 649200218Smav printf("%s%d: port %d status: %08x\n", 650200218Smav periph->periph_name, periph->unit_number, 651200218Smav softc->pm_step, res); 652200218Smav } 653199747Smav /* Report device speed. */ 654199747Smav if (xpt_create_path(&dpath, periph, 655199747Smav xpt_path_path_id(periph->path), 656199747Smav softc->pm_step, 0) == CAM_REQ_CMP) { 657199747Smav bzero(&cts, sizeof(cts)); 658203108Smav xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 659199747Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 660199747Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 661199747Smav cts.xport_specific.sata.revision = (res & 0x0f0) >> 4; 662199747Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION; 663199747Smav xpt_action((union ccb *)&cts); 664199747Smav xpt_free_path(dpath); 665199747Smav } 666198708Smav softc->found |= (1 << softc->pm_step); 667198708Smav softc->pm_step++; 668198708Smav } else { 669198708Smav if (softc->pm_try < 10) { 670198708Smav cam_freeze_devq(periph->path); 671198708Smav cam_release_devq(periph->path, 672198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 673198708Smav /*reduction*/0, 674198708Smav /*timeout*/10, 675198708Smav /*getcount_only*/0); 676198708Smav softc->pm_try++; 677198708Smav } else { 678200218Smav if (bootverbose) { 679200218Smav printf("%s%d: port %d status: %08x\n", 680200218Smav periph->periph_name, periph->unit_number, 681200218Smav softc->pm_step, res); 682200218Smav } 683198708Smav softc->found &= ~(1 << softc->pm_step); 684198708Smav if (xpt_create_path(&dpath, periph, 685198708Smav done_ccb->ccb_h.path_id, 686198708Smav softc->pm_step, 0) == CAM_REQ_CMP) { 687198708Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 688198708Smav xpt_free_path(dpath); 689198708Smav } 690198389Smav softc->pm_step++; 691198389Smav } 692198708Smav } 693198708Smav if (softc->pm_step >= softc->pm_ports) { 694198708Smav if (softc->reset & softc->found) { 695198708Smav cam_freeze_devq(periph->path); 696198708Smav cam_release_devq(periph->path, 697198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 698198708Smav /*reduction*/0, 699198708Smav /*timeout*/1000, 700198708Smav /*getcount_only*/0); 701198389Smav } 702198708Smav softc->state = PMP_STATE_CLEAR; 703198708Smav softc->pm_step = 0; 704198389Smav } 705198389Smav xpt_release_ccb(done_ccb); 706198708Smav xpt_schedule(periph, priority); 707198708Smav return; 708198389Smav case PMP_STATE_CLEAR: 709198708Smav softc->pm_step++; 710199321Smav if (softc->pm_step >= softc->pm_ports) { 711199321Smav softc->state = PMP_STATE_CONFIG; 712198708Smav softc->pm_step = 0; 713199321Smav } 714199321Smav xpt_release_ccb(done_ccb); 715199321Smav xpt_schedule(periph, priority); 716199321Smav return; 717199321Smav case PMP_STATE_CONFIG: 718203108Smav for (i = 0; i < softc->pm_ports; i++) { 719203108Smav union ccb *ccb; 720203108Smav 721203108Smav if ((softc->found & (1 << i)) == 0) 722203108Smav continue; 723203108Smav if (xpt_create_path(&dpath, periph, 724203108Smav xpt_path_path_id(periph->path), 725203108Smav i, 0) != CAM_REQ_CMP) { 726203108Smav printf("pmpdone: xpt_create_path failed" 727203108Smav ", bus scan halted\n"); 728203108Smav xpt_free_ccb(done_ccb); 729203108Smav goto done; 730203108Smav } 731203108Smav /* If we did hard reset to this device, inform XPT. */ 732203108Smav if ((softc->reset & softc->found & (1 << i)) != 0) 733203108Smav xpt_async(AC_SENT_BDR, dpath, NULL); 734203108Smav /* If rescan requested, scan this device. */ 735203108Smav if (softc->events & PMP_EV_RESCAN) { 736203108Smav ccb = xpt_alloc_ccb_nowait(); 737203108Smav if (ccb == NULL) { 738203108Smav xpt_free_path(dpath); 739203108Smav goto done; 740203108Smav } 741203108Smav xpt_setup_ccb(&ccb->ccb_h, dpath, CAM_PRIORITY_XPT); 742203108Smav xpt_rescan(ccb); 743203108Smav } else 744203108Smav xpt_free_path(dpath); 745198389Smav } 746198389Smav break; 747198389Smav default: 748198389Smav break; 749198389Smav } 750198708Smavdone: 751198708Smav xpt_release_ccb(done_ccb); 752198389Smav softc->state = PMP_STATE_NORMAL; 753203108Smav softc->events = 0; 754203108Smav xpt_release_boot(); 755198389Smav pmprelease(periph, -1); 756198389Smav cam_periph_release_locked(periph); 757198389Smav} 758198389Smav 759198389Smav#endif /* _KERNEL */ 760