ata_pmp.c revision 203108
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 203108 2010-01-28 08:41:30Z 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 union ccb saved_ccb; 105198389Smav struct task sysctl_task; 106198389Smav struct sysctl_ctx_list sysctl_ctx; 107198389Smav struct sysctl_oid *sysctl_tree; 108198389Smav}; 109198389Smav 110198389Smavstatic periph_init_t pmpinit; 111198389Smavstatic void pmpasync(void *callback_arg, u_int32_t code, 112198389Smav struct cam_path *path, void *arg); 113198389Smavstatic void pmpsysctlinit(void *context, int pending); 114198389Smavstatic periph_ctor_t pmpregister; 115198389Smavstatic periph_dtor_t pmpcleanup; 116198389Smavstatic periph_start_t pmpstart; 117198389Smavstatic periph_oninv_t pmponinvalidate; 118198389Smavstatic void pmpdone(struct cam_periph *periph, 119198389Smav union ccb *done_ccb); 120198389Smav 121198389Smav#ifndef PMP_DEFAULT_TIMEOUT 122198389Smav#define PMP_DEFAULT_TIMEOUT 30 /* Timeout in seconds */ 123198389Smav#endif 124198389Smav 125198389Smav#ifndef PMP_DEFAULT_RETRY 126198389Smav#define PMP_DEFAULT_RETRY 1 127198389Smav#endif 128198389Smav 129198389Smavstatic int pmp_retry_count = PMP_DEFAULT_RETRY; 130198389Smavstatic int pmp_default_timeout = PMP_DEFAULT_TIMEOUT; 131198389Smav 132198389SmavSYSCTL_NODE(_kern_cam, OID_AUTO, pmp, CTLFLAG_RD, 0, 133198389Smav "CAM Direct Access Disk driver"); 134198389SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, retry_count, CTLFLAG_RW, 135198389Smav &pmp_retry_count, 0, "Normal I/O retry count"); 136198389SmavTUNABLE_INT("kern.cam.pmp.retry_count", &pmp_retry_count); 137198389SmavSYSCTL_INT(_kern_cam_pmp, OID_AUTO, default_timeout, CTLFLAG_RW, 138198389Smav &pmp_default_timeout, 0, "Normal I/O timeout (in seconds)"); 139198389SmavTUNABLE_INT("kern.cam.pmp.default_timeout", &pmp_default_timeout); 140198389Smav 141198389Smavstatic struct periph_driver pmpdriver = 142198389Smav{ 143198389Smav pmpinit, "pmp", 144198708Smav TAILQ_HEAD_INITIALIZER(pmpdriver.units), /* generation */ 0, 145198708Smav CAM_PERIPH_DRV_EARLY 146198389Smav}; 147198389Smav 148198389SmavPERIPHDRIVER_DECLARE(pmp, pmpdriver); 149198389Smav 150198389SmavMALLOC_DEFINE(M_ATPMP, "ata_pmp", "ata_pmp buffers"); 151198389Smav 152198389Smavstatic void 153198389Smavpmpinit(void) 154198389Smav{ 155198389Smav cam_status status; 156198389Smav 157198389Smav /* 158198389Smav * Install a global async callback. This callback will 159198389Smav * receive async callbacks like "new device found". 160198389Smav */ 161198389Smav status = xpt_register_async(AC_FOUND_DEVICE, pmpasync, NULL, NULL); 162198389Smav 163198389Smav if (status != CAM_REQ_CMP) { 164198389Smav printf("pmp: Failed to attach master async callback " 165198389Smav "due to status 0x%x!\n", status); 166198389Smav } 167198389Smav} 168198389Smav 169198389Smavstatic void 170198389Smavpmpfreeze(struct cam_periph *periph, int mask) 171198389Smav{ 172198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 173198389Smav struct cam_path *dpath; 174198389Smav int i; 175198389Smav 176198389Smav mask &= ~softc->frozen; 177198389Smav for (i = 0; i < 15; i++) { 178198389Smav if ((mask & (1 << i)) == 0) 179198389Smav continue; 180198389Smav if (xpt_create_path(&dpath, periph, 181198389Smav xpt_path_path_id(periph->path), 182198389Smav i, 0) == CAM_REQ_CMP) { 183198389Smav softc->frozen |= (1 << i); 184200218Smav xpt_acquire_device(dpath->device); 185203108Smav cam_freeze_devq_arg(dpath, 186203108Smav RELSIM_RELEASE_RUNLEVEL, CAM_RL_BUS + 1); 187198389Smav xpt_free_path(dpath); 188198389Smav } 189198389Smav } 190198389Smav} 191198389Smav 192198389Smavstatic void 193198389Smavpmprelease(struct cam_periph *periph, int mask) 194198389Smav{ 195198389Smav struct pmp_softc *softc = (struct pmp_softc *)periph->softc; 196198389Smav struct cam_path *dpath; 197198389Smav int i; 198198389Smav 199198389Smav mask &= softc->frozen; 200198389Smav for (i = 0; i < 15; i++) { 201198389Smav if ((mask & (1 << i)) == 0) 202198389Smav continue; 203198389Smav if (xpt_create_path(&dpath, periph, 204198389Smav xpt_path_path_id(periph->path), 205198389Smav i, 0) == CAM_REQ_CMP) { 206198389Smav softc->frozen &= ~(1 << i); 207203108Smav cam_release_devq(dpath, 208203108Smav RELSIM_RELEASE_RUNLEVEL, 0, CAM_RL_BUS + 1, FALSE); 209200218Smav xpt_release_device(dpath->device); 210198389Smav xpt_free_path(dpath); 211198389Smav } 212198389Smav } 213198389Smav} 214198389Smav 215198389Smavstatic void 216198389Smavpmponinvalidate(struct cam_periph *periph) 217198389Smav{ 218198389Smav struct pmp_softc *softc; 219198389Smav struct cam_path *dpath; 220198389Smav int i; 221198389Smav 222198389Smav softc = (struct pmp_softc *)periph->softc; 223198389Smav 224198389Smav /* 225198389Smav * De-register any async callbacks. 226198389Smav */ 227198389Smav xpt_register_async(0, pmpasync, periph, periph->path); 228198389Smav 229198389Smav for (i = 0; i < 15; i++) { 230198389Smav if (xpt_create_path(&dpath, periph, 231198389Smav xpt_path_path_id(periph->path), 232198389Smav i, 0) == CAM_REQ_CMP) { 233198389Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 234198389Smav xpt_free_path(dpath); 235198389Smav } 236198389Smav } 237200218Smav pmprelease(periph, -1); 238198389Smav xpt_print(periph->path, "lost device\n"); 239198389Smav} 240198389Smav 241198389Smavstatic void 242198389Smavpmpcleanup(struct cam_periph *periph) 243198389Smav{ 244198389Smav struct pmp_softc *softc; 245198389Smav 246198389Smav softc = (struct pmp_softc *)periph->softc; 247198389Smav 248198389Smav xpt_print(periph->path, "removing device entry\n"); 249198389Smav cam_periph_unlock(periph); 250198389Smav 251198389Smav /* 252198389Smav * If we can't free the sysctl tree, oh well... 253198389Smav */ 254198389Smav if ((softc->flags & PMP_FLAG_SCTX_INIT) != 0 255198389Smav && sysctl_ctx_free(&softc->sysctl_ctx) != 0) { 256198389Smav xpt_print(periph->path, "can't remove sysctl context\n"); 257198389Smav } 258198389Smav 259198389Smav free(softc, M_DEVBUF); 260198389Smav cam_periph_lock(periph); 261198389Smav} 262198389Smav 263198389Smavstatic void 264198389Smavpmpasync(void *callback_arg, u_int32_t code, 265198389Smav struct cam_path *path, void *arg) 266198389Smav{ 267198389Smav struct cam_periph *periph; 268198389Smav struct pmp_softc *softc; 269198389Smav 270198389Smav periph = (struct cam_periph *)callback_arg; 271198389Smav switch (code) { 272198389Smav case AC_FOUND_DEVICE: 273198389Smav { 274198389Smav struct ccb_getdev *cgd; 275198389Smav cam_status status; 276198389Smav 277198389Smav cgd = (struct ccb_getdev *)arg; 278198389Smav if (cgd == NULL) 279198389Smav break; 280198389Smav 281198389Smav if (cgd->protocol != PROTO_SATAPM) 282198389Smav break; 283198389Smav 284198389Smav /* 285198389Smav * Allocate a peripheral instance for 286198389Smav * this device and start the probe 287198389Smav * process. 288198389Smav */ 289198389Smav status = cam_periph_alloc(pmpregister, pmponinvalidate, 290198389Smav pmpcleanup, pmpstart, 291198389Smav "pmp", CAM_PERIPH_BIO, 292198389Smav cgd->ccb_h.path, pmpasync, 293198389Smav AC_FOUND_DEVICE, cgd); 294198389Smav 295198389Smav if (status != CAM_REQ_CMP 296198389Smav && status != CAM_REQ_INPROG) 297198389Smav printf("pmpasync: Unable to attach to new device " 298198389Smav "due to status 0x%x\n", status); 299198389Smav break; 300198389Smav } 301198389Smav case AC_SCSI_AEN: 302198389Smav case AC_SENT_BDR: 303198389Smav case AC_BUS_RESET: 304198389Smav softc = (struct pmp_softc *)periph->softc; 305198389Smav cam_periph_async(periph, code, path, arg); 306203108Smav if (code == AC_SCSI_AEN) 307203108Smav softc->events |= PMP_EV_RESCAN; 308203108Smav else 309203108Smav softc->events |= PMP_EV_RESET; 310203108Smav if (code == AC_SCSI_AEN && softc->state != PMP_STATE_NORMAL) 311198389Smav break; 312203108Smav xpt_hold_boot(); 313203108Smav pmpfreeze(periph, softc->found); 314198389Smav if (code == AC_SENT_BDR || code == AC_BUS_RESET) 315198389Smav softc->found = 0; /* We have to reset everything. */ 316198708Smav if (softc->state == PMP_STATE_NORMAL) { 317203108Smav softc->state = PMP_STATE_PRECONFIG; 318198708Smav cam_periph_acquire(periph); 319203108Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 320198708Smav } else 321198708Smav softc->restart = 1; 322198389Smav break; 323198389Smav default: 324198389Smav cam_periph_async(periph, code, path, arg); 325198389Smav break; 326198389Smav } 327198389Smav} 328198389Smav 329198389Smavstatic void 330198389Smavpmpsysctlinit(void *context, int pending) 331198389Smav{ 332198389Smav struct cam_periph *periph; 333198389Smav struct pmp_softc *softc; 334198389Smav char tmpstr[80], tmpstr2[80]; 335198389Smav 336198389Smav periph = (struct cam_periph *)context; 337198389Smav if (cam_periph_acquire(periph) != CAM_REQ_CMP) 338198389Smav return; 339198389Smav 340198389Smav softc = (struct pmp_softc *)periph->softc; 341198389Smav snprintf(tmpstr, sizeof(tmpstr), "CAM PMP unit %d", periph->unit_number); 342198389Smav snprintf(tmpstr2, sizeof(tmpstr2), "%d", periph->unit_number); 343198389Smav 344198389Smav sysctl_ctx_init(&softc->sysctl_ctx); 345198389Smav softc->flags |= PMP_FLAG_SCTX_INIT; 346198389Smav softc->sysctl_tree = SYSCTL_ADD_NODE(&softc->sysctl_ctx, 347198389Smav SYSCTL_STATIC_CHILDREN(_kern_cam_pmp), OID_AUTO, tmpstr2, 348198389Smav CTLFLAG_RD, 0, tmpstr); 349198389Smav if (softc->sysctl_tree == NULL) { 350198389Smav printf("pmpsysctlinit: unable to allocate sysctl tree\n"); 351198389Smav cam_periph_release(periph); 352198389Smav return; 353198389Smav } 354198389Smav 355198389Smav cam_periph_release(periph); 356198389Smav} 357198389Smav 358198389Smavstatic cam_status 359198389Smavpmpregister(struct cam_periph *periph, void *arg) 360198389Smav{ 361198389Smav struct pmp_softc *softc; 362198389Smav struct ccb_getdev *cgd; 363198389Smav 364198389Smav cgd = (struct ccb_getdev *)arg; 365198389Smav if (periph == NULL) { 366198389Smav printf("pmpregister: periph was NULL!!\n"); 367198389Smav return(CAM_REQ_CMP_ERR); 368198389Smav } 369198389Smav 370198389Smav if (cgd == NULL) { 371198389Smav printf("pmpregister: no getdev CCB, can't register device\n"); 372198389Smav return(CAM_REQ_CMP_ERR); 373198389Smav } 374198389Smav 375198389Smav softc = (struct pmp_softc *)malloc(sizeof(*softc), M_DEVBUF, 376198389Smav M_NOWAIT|M_ZERO); 377198389Smav 378198389Smav if (softc == NULL) { 379198389Smav printf("pmpregister: Unable to probe new device. " 380198389Smav "Unable to allocate softc\n"); 381198389Smav return(CAM_REQ_CMP_ERR); 382198389Smav } 383198389Smav periph->softc = softc; 384198389Smav 385198389Smav softc->pm_pid = ((uint32_t *)&cgd->ident_data)[0]; 386198389Smav softc->pm_prv = ((uint32_t *)&cgd->ident_data)[1]; 387198389Smav TASK_INIT(&softc->sysctl_task, 0, pmpsysctlinit, periph); 388198389Smav 389198389Smav xpt_announce_periph(periph, NULL); 390198389Smav 391198389Smav /* 392198389Smav * Add async callbacks for bus reset and 393198389Smav * bus device reset calls. I don't bother 394198389Smav * checking if this fails as, in most cases, 395198389Smav * the system will function just fine without 396198389Smav * them and the only alternative would be to 397198389Smav * not attach the device on failure. 398198389Smav */ 399198389Smav xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE | 400198389Smav AC_SCSI_AEN, pmpasync, periph, periph->path); 401198389Smav 402198389Smav /* 403198389Smav * Take an exclusive refcount on the periph while pmpstart is called 404198389Smav * to finish the probe. The reference will be dropped in pmpdone at 405198389Smav * the end of probe. 406198389Smav */ 407198389Smav (void)cam_periph_acquire(periph); 408203108Smav xpt_hold_boot(); 409203108Smav softc->state = PMP_STATE_PORTS; 410203108Smav softc->events = PMP_EV_RESCAN; 411203108Smav xpt_schedule(periph, CAM_PRIORITY_DEV); 412198389Smav 413198389Smav return(CAM_REQ_CMP); 414198389Smav} 415198389Smav 416198389Smavstatic void 417198389Smavpmpstart(struct cam_periph *periph, union ccb *start_ccb) 418198389Smav{ 419203108Smav struct ccb_trans_settings cts; 420198389Smav struct ccb_ataio *ataio; 421198389Smav struct pmp_softc *softc; 422203108Smav struct cam_path *dpath; 423203108Smav int revision = 0; 424198389Smav 425198389Smav softc = (struct pmp_softc *)periph->softc; 426198389Smav ataio = &start_ccb->ataio; 427198708Smav 428198708Smav if (softc->restart) { 429198708Smav softc->restart = 0; 430203108Smav softc->state = min(softc->state, PMP_STATE_PRECONFIG); 431198708Smav } 432203108Smav /* Fetch user wanted device speed. */ 433203108Smav if (softc->state == PMP_STATE_RESET || 434203108Smav softc->state == PMP_STATE_CONNECT) { 435203108Smav if (xpt_create_path(&dpath, periph, 436203108Smav xpt_path_path_id(periph->path), 437203108Smav softc->pm_step, 0) == CAM_REQ_CMP) { 438203108Smav bzero(&cts, sizeof(cts)); 439203108Smav xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 440203108Smav cts.ccb_h.func_code = XPT_GET_TRAN_SETTINGS; 441203108Smav cts.type = CTS_TYPE_USER_SETTINGS; 442203108Smav xpt_action((union ccb *)&cts); 443203108Smav if (cts.xport_specific.sata.valid & CTS_SATA_VALID_REVISION) 444203108Smav revision = cts.xport_specific.sata.revision; 445203108Smav xpt_free_path(dpath); 446203108Smav } 447203108Smav } 448198389Smav switch (softc->state) { 449198389Smav case PMP_STATE_PORTS: 450198389Smav cam_fill_ataio(ataio, 451198389Smav pmp_retry_count, 452198389Smav pmpdone, 453198389Smav /*flags*/CAM_DIR_NONE, 454198389Smav 0, 455198389Smav /*data_ptr*/NULL, 456198389Smav /*dxfer_len*/0, 457198389Smav pmp_default_timeout * 1000); 458198389Smav ata_pm_read_cmd(ataio, 2, 15); 459198389Smav break; 460199321Smav case PMP_STATE_PRECONFIG: 461198389Smav cam_fill_ataio(ataio, 462198389Smav pmp_retry_count, 463198389Smav pmpdone, 464198389Smav /*flags*/CAM_DIR_NONE, 465198389Smav 0, 466198389Smav /*data_ptr*/NULL, 467198389Smav /*dxfer_len*/0, 468198389Smav pmp_default_timeout * 1000); 469199321Smav ata_pm_write_cmd(ataio, 0x60, 15, 0x0); 470198389Smav break; 471198389Smav case PMP_STATE_RESET: 472198389Smav cam_fill_ataio(ataio, 473198389Smav pmp_retry_count, 474198389Smav pmpdone, 475198389Smav /*flags*/CAM_DIR_NONE, 476198389Smav 0, 477198389Smav /*data_ptr*/NULL, 478198389Smav /*dxfer_len*/0, 479198389Smav pmp_default_timeout * 1000); 480198389Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 481203108Smav (revision << 4) | 482203108Smav ((softc->found & (1 << softc->pm_step)) ? 0 : 1)); 483198389Smav break; 484198389Smav case PMP_STATE_CONNECT: 485198389Smav cam_fill_ataio(ataio, 486198389Smav pmp_retry_count, 487198389Smav pmpdone, 488198389Smav /*flags*/CAM_DIR_NONE, 489198389Smav 0, 490198389Smav /*data_ptr*/NULL, 491198389Smav /*dxfer_len*/0, 492198389Smav pmp_default_timeout * 1000); 493203108Smav ata_pm_write_cmd(ataio, 2, softc->pm_step, 494203108Smav (revision << 4)); 495198389Smav break; 496198389Smav case PMP_STATE_CHECK: 497198389Smav cam_fill_ataio(ataio, 498198389Smav pmp_retry_count, 499198389Smav pmpdone, 500198389Smav /*flags*/CAM_DIR_NONE, 501198389Smav 0, 502198389Smav /*data_ptr*/NULL, 503198389Smav /*dxfer_len*/0, 504198389Smav pmp_default_timeout * 1000); 505198389Smav ata_pm_read_cmd(ataio, 0, softc->pm_step); 506198389Smav break; 507198389Smav case PMP_STATE_CLEAR: 508198708Smav softc->reset = 0; 509198389Smav cam_fill_ataio(ataio, 510198389Smav pmp_retry_count, 511198389Smav pmpdone, 512198389Smav /*flags*/CAM_DIR_NONE, 513198389Smav 0, 514198389Smav /*data_ptr*/NULL, 515198389Smav /*dxfer_len*/0, 516198389Smav pmp_default_timeout * 1000); 517198389Smav ata_pm_write_cmd(ataio, 1, softc->pm_step, 0xFFFFFFFF); 518198389Smav break; 519199321Smav case PMP_STATE_CONFIG: 520199321Smav cam_fill_ataio(ataio, 521199321Smav pmp_retry_count, 522199321Smav pmpdone, 523199321Smav /*flags*/CAM_DIR_NONE, 524199321Smav 0, 525199321Smav /*data_ptr*/NULL, 526199321Smav /*dxfer_len*/0, 527199321Smav pmp_default_timeout * 1000); 528199321Smav ata_pm_write_cmd(ataio, 0x60, 15, 0xf); 529199321Smav break; 530198389Smav default: 531198389Smav break; 532198389Smav } 533198389Smav xpt_action(start_ccb); 534198389Smav} 535198389Smav 536198389Smavstatic void 537198389Smavpmpdone(struct cam_periph *periph, union ccb *done_ccb) 538198389Smav{ 539199747Smav struct ccb_trans_settings cts; 540198389Smav struct pmp_softc *softc; 541198389Smav struct ccb_ataio *ataio; 542198389Smav struct cam_path *path, *dpath; 543198708Smav u_int32_t priority, res; 544203108Smav int i; 545198389Smav 546198389Smav softc = (struct pmp_softc *)periph->softc; 547198389Smav ataio = &done_ccb->ataio; 548198389Smav 549198389Smav CAM_DEBUG(done_ccb->ccb_h.path, CAM_DEBUG_TRACE, ("pmpdone\n")); 550198389Smav 551198389Smav path = done_ccb->ccb_h.path; 552198389Smav priority = done_ccb->ccb_h.pinfo.priority; 553198389Smav 554198708Smav if ((done_ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 555198708Smav if (cam_periph_error(done_ccb, 0, 0, 556198708Smav &softc->saved_ccb) == ERESTART) { 557198389Smav return; 558198389Smav } else if ((done_ccb->ccb_h.status & CAM_DEV_QFRZN) != 0) { 559198708Smav cam_release_devq(done_ccb->ccb_h.path, 560198708Smav /*relsim_flags*/0, 561198708Smav /*reduction*/0, 562198708Smav /*timeout*/0, 563198708Smav /*getcount_only*/0); 564198389Smav } 565198708Smav goto done; 566198708Smav } 567198708Smav 568198708Smav if (softc->restart) { 569198708Smav softc->restart = 0; 570198389Smav xpt_release_ccb(done_ccb); 571203108Smav softc->state = min(softc->state, PMP_STATE_PRECONFIG); 572198708Smav xpt_schedule(periph, priority); 573198708Smav return; 574198708Smav } 575198708Smav 576198708Smav switch (softc->state) { 577198708Smav case PMP_STATE_PORTS: 578198708Smav softc->pm_ports = (done_ccb->ataio.res.lba_high << 24) + 579198708Smav (done_ccb->ataio.res.lba_mid << 16) + 580198708Smav (done_ccb->ataio.res.lba_low << 8) + 581198708Smav done_ccb->ataio.res.sector_count; 582199321Smav /* This PMP declares 6 ports, while only 5 of them are real. 583198708Smav * Port 5 is enclosure management bridge port, which has implementation 584198708Smav * problems, causing probe faults. Hide it for now. */ 585198708Smav if (softc->pm_pid == 0x37261095 && softc->pm_ports == 6) 586198708Smav softc->pm_ports = 5; 587199321Smav /* This PMP declares 7 ports, while only 5 of them are real. 588198708Smav * Port 5 is some fake "Config Disk" with 640 sectors size, 589198708Smav * port 6 is enclosure management bridge port. 590198708Smav * Both fake ports has implementation problems, causing 591198708Smav * probe faults. Hide them for now. */ 592198708Smav if (softc->pm_pid == 0x47261095 && softc->pm_ports == 7) 593198708Smav softc->pm_ports = 5; 594199321Smav /* These PMPs declare one more port then actually have, 595199321Smav * for configuration purposes. Hide it for now. */ 596199321Smav if (softc->pm_pid == 0x57231095 || softc->pm_pid == 0x57331095 || 597199321Smav softc->pm_pid == 0x57341095 || softc->pm_pid == 0x57441095) 598199321Smav softc->pm_ports--; 599200218Smav printf("%s%d: %d fan-out ports\n", 600200218Smav periph->periph_name, periph->unit_number, 601200218Smav softc->pm_ports); 602199321Smav softc->state = PMP_STATE_PRECONFIG; 603198708Smav xpt_release_ccb(done_ccb); 604198708Smav xpt_schedule(periph, priority); 605198708Smav return; 606199321Smav case PMP_STATE_PRECONFIG: 607198708Smav softc->pm_step = 0; 608198708Smav softc->state = PMP_STATE_RESET; 609198708Smav softc->reset |= ~softc->found; 610198389Smav xpt_release_ccb(done_ccb); 611198708Smav xpt_schedule(periph, priority); 612198708Smav return; 613198389Smav case PMP_STATE_RESET: 614198708Smav softc->pm_step++; 615198708Smav if (softc->pm_step >= softc->pm_ports) { 616198708Smav softc->pm_step = 0; 617198708Smav cam_freeze_devq(periph->path); 618198708Smav cam_release_devq(periph->path, 619198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 620198708Smav /*reduction*/0, 621198708Smav /*timeout*/5, 622198708Smav /*getcount_only*/0); 623198708Smav softc->state = PMP_STATE_CONNECT; 624198389Smav } 625198389Smav xpt_release_ccb(done_ccb); 626198708Smav xpt_schedule(periph, priority); 627198708Smav return; 628198389Smav case PMP_STATE_CONNECT: 629198708Smav softc->pm_step++; 630198708Smav if (softc->pm_step >= softc->pm_ports) { 631198708Smav softc->pm_step = 0; 632198708Smav softc->pm_try = 0; 633198708Smav cam_freeze_devq(periph->path); 634198708Smav cam_release_devq(periph->path, 635198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 636198708Smav /*reduction*/0, 637198708Smav /*timeout*/10, 638198708Smav /*getcount_only*/0); 639198708Smav softc->state = PMP_STATE_CHECK; 640198389Smav } 641198389Smav xpt_release_ccb(done_ccb); 642198708Smav xpt_schedule(periph, priority); 643198708Smav return; 644198389Smav case PMP_STATE_CHECK: 645198708Smav res = (done_ccb->ataio.res.lba_high << 24) + 646198708Smav (done_ccb->ataio.res.lba_mid << 16) + 647198708Smav (done_ccb->ataio.res.lba_low << 8) + 648198708Smav done_ccb->ataio.res.sector_count; 649198708Smav if ((res & 0xf0f) == 0x103 && (res & 0x0f0) != 0) { 650200218Smav if (bootverbose) { 651200218Smav printf("%s%d: port %d status: %08x\n", 652200218Smav periph->periph_name, periph->unit_number, 653200218Smav softc->pm_step, res); 654200218Smav } 655199747Smav /* Report device speed. */ 656199747Smav if (xpt_create_path(&dpath, periph, 657199747Smav xpt_path_path_id(periph->path), 658199747Smav softc->pm_step, 0) == CAM_REQ_CMP) { 659199747Smav bzero(&cts, sizeof(cts)); 660203108Smav xpt_setup_ccb(&cts.ccb_h, dpath, CAM_PRIORITY_NONE); 661199747Smav cts.ccb_h.func_code = XPT_SET_TRAN_SETTINGS; 662199747Smav cts.type = CTS_TYPE_CURRENT_SETTINGS; 663199747Smav cts.xport_specific.sata.revision = (res & 0x0f0) >> 4; 664199747Smav cts.xport_specific.sata.valid = CTS_SATA_VALID_REVISION; 665199747Smav xpt_action((union ccb *)&cts); 666199747Smav xpt_free_path(dpath); 667199747Smav } 668198708Smav softc->found |= (1 << softc->pm_step); 669198708Smav softc->pm_step++; 670198708Smav } else { 671198708Smav if (softc->pm_try < 10) { 672198708Smav cam_freeze_devq(periph->path); 673198708Smav cam_release_devq(periph->path, 674198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 675198708Smav /*reduction*/0, 676198708Smav /*timeout*/10, 677198708Smav /*getcount_only*/0); 678198708Smav softc->pm_try++; 679198708Smav } else { 680200218Smav if (bootverbose) { 681200218Smav printf("%s%d: port %d status: %08x\n", 682200218Smav periph->periph_name, periph->unit_number, 683200218Smav softc->pm_step, res); 684200218Smav } 685198708Smav softc->found &= ~(1 << softc->pm_step); 686198708Smav if (xpt_create_path(&dpath, periph, 687198708Smav done_ccb->ccb_h.path_id, 688198708Smav softc->pm_step, 0) == CAM_REQ_CMP) { 689198708Smav xpt_async(AC_LOST_DEVICE, dpath, NULL); 690198708Smav xpt_free_path(dpath); 691198708Smav } 692198389Smav softc->pm_step++; 693198389Smav } 694198708Smav } 695198708Smav if (softc->pm_step >= softc->pm_ports) { 696198708Smav if (softc->reset & softc->found) { 697198708Smav cam_freeze_devq(periph->path); 698198708Smav cam_release_devq(periph->path, 699198708Smav RELSIM_RELEASE_AFTER_TIMEOUT, 700198708Smav /*reduction*/0, 701198708Smav /*timeout*/1000, 702198708Smav /*getcount_only*/0); 703198389Smav } 704198708Smav softc->state = PMP_STATE_CLEAR; 705198708Smav softc->pm_step = 0; 706198389Smav } 707198389Smav xpt_release_ccb(done_ccb); 708198708Smav xpt_schedule(periph, priority); 709198708Smav return; 710198389Smav case PMP_STATE_CLEAR: 711198708Smav softc->pm_step++; 712199321Smav if (softc->pm_step >= softc->pm_ports) { 713199321Smav softc->state = PMP_STATE_CONFIG; 714198708Smav softc->pm_step = 0; 715199321Smav } 716199321Smav xpt_release_ccb(done_ccb); 717199321Smav xpt_schedule(periph, priority); 718199321Smav return; 719199321Smav case PMP_STATE_CONFIG: 720203108Smav for (i = 0; i < softc->pm_ports; i++) { 721203108Smav union ccb *ccb; 722203108Smav 723203108Smav if ((softc->found & (1 << i)) == 0) 724203108Smav continue; 725203108Smav if (xpt_create_path(&dpath, periph, 726203108Smav xpt_path_path_id(periph->path), 727203108Smav i, 0) != CAM_REQ_CMP) { 728203108Smav printf("pmpdone: xpt_create_path failed" 729203108Smav ", bus scan halted\n"); 730203108Smav xpt_free_ccb(done_ccb); 731203108Smav goto done; 732203108Smav } 733203108Smav /* If we did hard reset to this device, inform XPT. */ 734203108Smav if ((softc->reset & softc->found & (1 << i)) != 0) 735203108Smav xpt_async(AC_SENT_BDR, dpath, NULL); 736203108Smav /* If rescan requested, scan this device. */ 737203108Smav if (softc->events & PMP_EV_RESCAN) { 738203108Smav ccb = xpt_alloc_ccb_nowait(); 739203108Smav if (ccb == NULL) { 740203108Smav xpt_free_path(dpath); 741203108Smav goto done; 742203108Smav } 743203108Smav xpt_setup_ccb(&ccb->ccb_h, dpath, CAM_PRIORITY_XPT); 744203108Smav xpt_rescan(ccb); 745203108Smav } else 746203108Smav xpt_free_path(dpath); 747198389Smav } 748198389Smav break; 749198389Smav default: 750198389Smav break; 751198389Smav } 752198708Smavdone: 753198708Smav xpt_release_ccb(done_ccb); 754198389Smav softc->state = PMP_STATE_NORMAL; 755203108Smav softc->events = 0; 756203108Smav xpt_release_boot(); 757198389Smav pmprelease(periph, -1); 758198389Smav cam_periph_release_locked(periph); 759198389Smav} 760198389Smav 761198389Smav#endif /* _KERNEL */ 762